With javac 1.8.0_77 this class does not compile:
import java.util.function.*;
public class xx {
final Object obj;
final Supplier<Object> supplier1 = new Supplier<Object>() {
@Override
public Object get() {
return xx.this.obj;
}
};
final Supplier<Object> supplier2 = () -> { return this.obj; };
xx(Object obj) {
this.obj = obj;
}
}
Here's the error:
xx.java:12: error: variable obj might not have been initialized
final Supplier<Object> supplier2 = () -> { return this.obj; };
^
1 error
Questions:
@FunctionalInterface
lamba implementation (supplier2
) differently from its equivalent inner class implementation (supplier1
) in this respect?EDITED TO ADD (2022/9/21)
FYI here's a simple compiler patch that fixes this. It causes lambdas to be treated like non-constructor methods with respect to field initialization (namely, ignore them) in Flow.AssignAnalyzer
:
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
index 20abb281211..7e77d594143 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
@@ -2820,30 +2909,33 @@ public class Flow {
@Override
public void visitLambda(JCLambda tree) {
final Bits prevUninits = new Bits(uninits);
final Bits prevInits = new Bits(inits);
int returnadrPrev = returnadr;
+ int firstadrPrev = firstadr;
int nextadrPrev = nextadr;
ListBuffer<PendingExit> prevPending = pendingExits;
try {
returnadr = nextadr;
+ firstadr = nextadr;
pendingExits = new ListBuffer<>();
for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
JCVariableDecl def = l.head;
scan(def);
inits.incl(def.sym.adr);
uninits.excl(def.sym.adr);
}
if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
scanExpr(tree.body);
} else {
scan(tree.body);
}
}
finally {
returnadr = returnadrPrev;
uninits.assign(prevUninits);
inits.assign(prevInits);
pendingExits = prevPending;
+ firstadr = firstadrPrev;
nextadr = nextadrPrev;
}
}
Browsing through the JLS changes from JSR 335, this looks like an omission to me:
supplier1
.In fact the only change in Chap.16 is (using bold type face for additions):
Throughout the rest of this chapter, we will, unless explicitly stated otherwise, write V to represent an in-scope (6.3) local variable or a blank final field
(for rules of definite assignment) or a blank final variable (for rules of definite unassignment).
At the bottom line, compilers seem to be right in not complaining in the lambda case, but for consistency JLS should probably be amended to cover this case, too.
Edit:: OpenJDK already has a spec bug for this, changes are being proposed as we speak.