Java 11 var in Lambda Parameters with Examples
Introduction
Java 10 introduced the
(Note - This tutorial assumes you know lambda expressionsClick to read: lambda expressions and the var keyword for local variablesClick to read: var keyword for local variables.) Three ways to declare lambda parameters Since Java 8, the parameters of a lambda could either be explicitly typed, or implicitly typed, in which case the compiler infers their types from the functional interface. Java 11 adds a third way, which uses
OUTPUT of the above code
Explanation of the code
Why var was added: annotations and modifiers
Annotations and modifiers can only be written on a parameter that has a type in front of it. An implicitly typed parameter such as
OUTPUT of the above code
Explanation of the code
OUTPUT on compiling the above code
And this one breaks the second rule -
OUTPUT on compiling the above code
The errors for this one are less helpful. Without parentheses, the compiler does not see a lambda at all - it reads
When to use var in lambda parameters
Implicitly typed parameters such as
var keyword for local variables. Java 11 (JEP 323) extended it to the parameters of lambda expressions. This tutorial explains var in lambda parameters in Java 11 with examples. We will first recap the two ways of declaring lambda parameters which already existed, and see what the var form adds. We will then see the main reason the feature was added - putting annotations and modifiers such as final on lambda parameters. Lastly, we will go through the rules the compiler enforces, along with the errors it gives when they are broken.(Note - This tutorial assumes you know lambda expressionsClick to read: lambda expressions and the var keyword for local variablesClick to read: var keyword for local variables.) Three ways to declare lambda parameters Since Java 8, the parameters of a lambda could either be explicitly typed, or implicitly typed, in which case the compiler infers their types from the functional interface. Java 11 adds a third way, which uses
var -
Explicit, implicit and var lambda parameters
//LambdaParamStyles.java
import java.util.function.BiFunction;
public class LambdaParamStyles {
public static void main(String[] args) {
// 1. Explicitly typed (Java 8)
BiFunction<String, Integer, String> explicit = (String s, Integer n) -> s.repeat(n);
// 2. Implicitly typed (Java 8)
BiFunction<String, Integer, String> implicit = (s, n) -> s.repeat(n);
// 3. var (Java 11)
BiFunction<String, Integer, String> withVar = (var s, var n) -> s.repeat(n);
System.out.println(explicit.apply("ab", 2));
System.out.println(implicit.apply("cd", 2));
System.out.println(withVar.apply("ef", 2));
}
}
abab cdcd efef
- All three lambdas compile to exactly the same thing. With
var, the types ofsandnare inferred asStringandIntegerfromBiFunction<String, Integer, String>, just as they are for the implicitly typed lambda. - So, on its own,
(var s, var n)is only a longer way of writing(s, n). The reason to use it is explained next.
s has nowhere to put them, so before Java 11 the only option was to write out the full type, which can be long. var gives you a place to put the annotation while the compiler still infers the type -
Annotations and final on lambda parameters
//AnnotatedLambda.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.BiConsumer;
public class AnnotatedLambda {
@Target(ElementType.PARAMETER)
@interface NonNull { }
public static void main(String[] args) {
Map<String, List<Integer>> marks = new TreeMap<>(Map.of(
"Tom", List.of(78, 91), "Harry", List.of(85, 64)));
// Without var, annotating the parameters needs the full types:
BiConsumer<String, List<Integer>> before =
(@NonNull String name, @NonNull List<Integer> scores) -> System.out.println(name + " " + scores);
// With var, the types are inferred and the annotations still fit:
BiConsumer<String, List<Integer>> after =
(@NonNull var name, final var scores) -> System.out.println(name + " averaged "
+ scores.stream().mapToInt(Integer::intValue).average().orElse(0));
marks.forEach(before);
marks.forEach(after);
}
}
Harry [85, 64] Tom [78, 91] Harry averaged 74.5 Tom averaged 84.5
@NonNullis a simple annotation which can be placed on parameters. In real projects you would use an annotation from a library such as the Checker Framework or JSpecify, which tools then use to check fornulls.- In
before, the annotations forced us to writeStringandList<Integer>. Inafter,@NonNull var namekeeps the annotation but lets the compiler infer the type. final var scoresmakes the parameter final, so assigning toscoresinside the lambda would be a compile error. This was also not possible with an implicitly typed parameter.varalso makes lambda parameters consistent with local variables, which can be declared withvarsince Java 10.
- All or nothing - if one parameter uses
var, all of them must. You cannot mixvarwith explicitly typed or implicitly typed parameters. - Parentheses are required - a single implicitly typed parameter can be written without parentheses, as in
s -> s.length(), butvar s -> s.length()is not allowed. Write(var s) -> s.length(). - Only in lambdas -
varis still not allowed for the parameters of methods and constructors.
Mixing var with other parameter styles
//VarLambdaMixing.java
import java.util.function.BiFunction;
public class VarLambdaMixing {
BiFunction<String, Integer, String> mixImplicit = (var s, n) -> s.repeat(n);
BiFunction<String, Integer, String> mixExplicit = (var s, Integer n) -> s.repeat(n);
}
VarLambdaMixing.java:5: error: invalid lambda parameter declaration
BiFunction<String, Integer, String> mixImplicit = (var s, n) -> s.repeat(n);
^
(cannot mix 'var' and implicitly-typed parameters)
VarLambdaMixing.java:6: error: invalid lambda parameter declaration
BiFunction<String, Integer, String> mixExplicit = (var s, Integer n) -> s.repeat(n);
^
(cannot mix 'var' and explicitly-typed parameters)
2 errors
var without parentheses
//VarLambdaParens.java
import java.util.function.Function;
public class VarLambdaParens {
Function<String, Integer> length = var s -> s.length();
}
VarLambdaParens.java:5: error: ';' expected
Function<String, Integer> length = var s -> s.length();
^
VarLambdaParens.java:5: error: <identifier> expected
Function<String, Integer> length = var s -> s.length();
^
VarLambdaParens.java:5: error: <identifier> expected
Function<String, Integer> length = var s -> s.length();
^
3 errors
var s as the start of a variable declaration, and reports the syntax errors which follow from that. If you see ';' expected pointing at a lambda, check for a var parameter without parentheses.
(s, n) -> ... remain the shortest and most readable form, and are the right choice for most lambdas. Use var when you need to add an annotation or the final modifier to a lambda parameter. Use explicit types when the type is not obvious and writing it makes the code easier to read.
Summary
In this tutorial we saw that Java 11 allows var for lambda parameters, in addition to the explicitly typed and implicitly typed forms of Java 8. We saw that the main use of var here is to add annotations and final to lambda parameters without writing their full types. Lastly, we went through the rules - var must be used for all the parameters or none, and the parameters must be in parentheses - along with the compiler errors for breaking them. In the next tutorial, we will see how Java 11 can run single-file source code programsClick to read tutorial: Java 11: Run Single-File Source Code Programs with java directly with the java command.Continue Reading Java 11 Tutorials
Java 11: Run Single-File Source Code Programs with javaClick to read tutorial: Java 11: Run Single-File Source Code Programs with java Java 11 String Methods: isBlank, lines, strip, repeatClick to read tutorial: Java 11 String Methods: isBlank, lines, strip, repeat Overview of New Features in Java 11Click to read tutorial: Overview of New Features in Java 11 Java 11 API Additions: Files.readString, Predicate.notClick to read tutorial: Java 11 API Additions: Files.readString, Predicate.not Java 11 HTTP Client API Tutorial with ExamplesClick to read tutorial: Java 11 HTTP Client API Tutorial with Examples Java 11 Removed Modules: Java EE, CORBA and JavaFXClick to read tutorial: Java 11 Removed Modules: Java EE, CORBA and JavaFX
Java 11: Run Single-File Source Code Programs with javaClick to read tutorial: Java 11: Run Single-File Source Code Programs with java Java 11 String Methods: isBlank, lines, strip, repeatClick to read tutorial: Java 11 String Methods: isBlank, lines, strip, repeat Overview of New Features in Java 11Click to read tutorial: Overview of New Features in Java 11 Java 11 API Additions: Files.readString, Predicate.notClick to read tutorial: Java 11 API Additions: Files.readString, Predicate.not Java 11 HTTP Client API Tutorial with ExamplesClick to read tutorial: Java 11 HTTP Client API Tutorial with Examples Java 11 Removed Modules: Java EE, CORBA and JavaFXClick to read tutorial: Java 11 Removed Modules: Java EE, CORBA and JavaFX