Java 11 JEP 323:Lambda参数var声明及修饰符合规性问询
Great question! Let's break down the key technical details of JEP 323, which brings var declarations to lambda parameters—building on your understanding of final modifiers and the example code you shared.
Core Technical Mechanics
1. Type Inference Logic
Just like with local variable var, the compiler infers the type of lambda parameters marked with var from the functional interface's abstract method signature. For your example:
ITest divide = (@ATest var x, final var y) -> x / y;
The compiler looks at the abstract method defined in ITest (e.g., something like int apply(int a, int b)), then maps var x and var y to the corresponding parameter types from that method. No extra type information is needed from you—the inference is fully context-driven.
2. Allowed Modifiers & Annotations
One of the biggest wins of this feature is enabling modifiers on inferred lambda parameters, which was impossible with the old "implicit parameter" syntax (your example #2 is illegal for exactly this reason). Here's what's allowed:
- Final modifier: As you noted, this aligns with immutable design principles. Marking
var yasfinalensures the parameter can't be reassigned within the lambda body—just like a final local variable. - Annotations: Custom annotations (like
@ATest) or built-in ones (like@Nullable) can be applied directly tovarparameters, which is useful for static analysis tools or framework requirements. - Restrictions: You can't use access modifiers (
public,private,protected) orstaticwithvarlambda parameters—since lambda parameters are inherently local to the lambda body. Also, you can't mixvarwith explicit types (e.g.,(var x, int y)is invalid) or mixvarwith implicit parameters (e.g.,(var x, y)is invalid).
3. Backward Compatibility
JEP 323 is fully backward-compatible. Your existing lambda code (like (x, y) -> x / y) still works exactly as before. This feature only adds an additional syntax option—no breaking changes to existing Java codebases.
4. Edge Cases to Note
- Generic Type Inference: If the functional interface uses generics, the compiler infers the generic type correctly for
varparameters. For example, if you have aFunction<List<String>, String>, the lambda(var list) -> list.get(0)will inferlistasList<String>. - Varargs: You can use
varwith varargs parameters too—just add the...aftervar:(var... args) -> Arrays.stream(args).sum(). The compiler will infer the varargs type from the functional interface.
Why Your Example #2 Is Illegal
To circle back to your code snippets:
/* #2 旧式隐式参数使用修饰符 => 非法 */ ITest divide = (@ATest x, final y) -> x / y;
Before Java 11, if you omitted the parameter type (implicit parameter), you couldn't apply any modifiers or annotations to it. JEP 323 fixes this gap by letting you use var to keep type inference while still allowing modifiers and annotations—hence why example #1 is valid.
内容的提问来源于stack exchange,提问作者Rann Lifshitz

