admin管理员组文章数量:1401291
A private lambda function is accessing a private final
class member that is initialised in the class constructor. However, this code pattern compiles with error: variable num might not have been initialized
public class Main {
private final int num;
public Main() {num = 7;}
private java.util.function.Supplier getNum = () -> num;
public void printNum() {
System.out.println(getNum.get());
}
public static void main(String[] args) {
Main main = new Main();
main.printNum();
}
}
However, the following patterns are fine:
i. Move lambda definition inside a method
public class Main {
private final int num;
public Main() {num = 7;}
private java.util.function.Supplier getNum;
public void printNum() {
getNum = () -> num;
System.out.println(getNum.get());
}
public static void main(String[] args) {
Main main = new Main();
main.printNum();
}
}
ii. Local lambda inside a method
public class Main {
private final int num;
public Main() {num = 7;}
public void printNum() {
java.util.function.Supplier getNum = () -> num;
System.out.println(getNum.get());
}
public static void main(String[] args) {
Main main = new Main();
main.printNum();
}
}
iii. Add this
before the class member and cast this
to the class name
public class Main {
private final int num;
public Main() {num = 7;}
private java.util.function.Supplier getNum = () -> ((Main) this).num;
public void printNum() {
System.out.println(getNum.get());
}
public static void main(String[] args) {
Main main = new Main();
main.printNum();
}
}
Could someone please explain what is going on above for each case? If it is compiler specific, I was testing on OpenJDK 11. Thank you.
P.S. a solution so that no this
casting while the lambda can be shared among class methods is to also initialise it inside the class constructor
public class Main {
private final int num;
private final java.util.function.Supplier getNum;
public Main() {num = 7; getNum = () -> num;}
public void printNum() {
System.out.println(getNum.get());
}
public static void main(String[] args) {
Main main = new Main();
main.printNum();
}
}
A private lambda function is accessing a private final
class member that is initialised in the class constructor. However, this code pattern compiles with error: variable num might not have been initialized
public class Main {
private final int num;
public Main() {num = 7;}
private java.util.function.Supplier getNum = () -> num;
public void printNum() {
System.out.println(getNum.get());
}
public static void main(String[] args) {
Main main = new Main();
main.printNum();
}
}
However, the following patterns are fine:
i. Move lambda definition inside a method
public class Main {
private final int num;
public Main() {num = 7;}
private java.util.function.Supplier getNum;
public void printNum() {
getNum = () -> num;
System.out.println(getNum.get());
}
public static void main(String[] args) {
Main main = new Main();
main.printNum();
}
}
ii. Local lambda inside a method
public class Main {
private final int num;
public Main() {num = 7;}
public void printNum() {
java.util.function.Supplier getNum = () -> num;
System.out.println(getNum.get());
}
public static void main(String[] args) {
Main main = new Main();
main.printNum();
}
}
iii. Add this
before the class member and cast this
to the class name
public class Main {
private final int num;
public Main() {num = 7;}
private java.util.function.Supplier getNum = () -> ((Main) this).num;
public void printNum() {
System.out.println(getNum.get());
}
public static void main(String[] args) {
Main main = new Main();
main.printNum();
}
}
Could someone please explain what is going on above for each case? If it is compiler specific, I was testing on OpenJDK 11. Thank you.
P.S. a solution so that no this
casting while the lambda can be shared among class methods is to also initialise it inside the class constructor
public class Main {
private final int num;
private final java.util.function.Supplier getNum;
public Main() {num = 7; getNum = () -> num;}
public void printNum() {
System.out.println(getNum.get());
}
public static void main(String[] args) {
Main main = new Main();
main.printNum();
}
}
Share
Improve this question
edited Mar 25 at 16:55
David Conrad
16.4k3 gold badges49 silver badges59 bronze badges
asked Mar 25 at 6:04
user1589188user1589188
5,73821 gold badges78 silver badges153 bronze badges
1 Answer
Reset to default 6The rules specified in Chapter 16 - Definite Assignment of the language specification are relevant here.
An access to its value consists of the simple name of the variable (or, for a field, the simple name of the field qualified by
this
) occurring anywhere in an expression except as the left-hand operand of the simple assignment operator=
.For every access of a local variable declared by a statement
x
, or blank final fieldx
,x
must be definitely assigned before the access, or a compile-time error occurs.
Just from the first paragraph, we can see that the expression ((Main) this).num
is not considered an "access" of a blank final field, as far as definite assignment is concerned, and therefore definite assignment analysis does not apply to it. Just writing num
, or this.num
are "accesses".
We will show that in the first code snippet, num
is not definitely assigned before the access in () -> num
.
16.9:
Let
C
be a class, and letV
be a blank final non-static member field ofC
, declared inC
. Then:
V
is definitely unassigned (and moreover is not definitely assigned) before the leftmost instance initializer or instance variable initializer ofC
.
() -> num
is the variable initialiser for the field getNum
. This is also the first (leftmost) variable initialiser of Main
. Therefore, num
is not definitely assigned before () -> num
.
Then 16.1.10 says:
If an expression is a lambda expression, then the following rules apply:
V
is definitely assigned before the expression or block that is the lambda body iffV
is definitely assigned before the lambda expression.
Notice that this is "iff", not just "if". As we have established, num
is not definitely assigned before the lambda expression, so num
is not definitely assigned before the lambda body expression, where the access occurs.
In cases i and ii, the access occurs in a method. 16.2.2 says:
A blank final member field
V
is definitely assigned (and moreover is not definitely unassigned) before the block that is the body of any method in the scope ofV
and before the declaration of any class declared within the scope ofV
.
Therefore, num
is already definitely assigned even before the method body. From here you can easily derive that it is definitely assigned before () -> num
, and therefore definitely assigned before the access.
本文标签: Java does not allow using private final class member in lambda under certain patternStack Overflow
版权声明:本文标题:Java does not allow using private final class member in lambda under certain pattern - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744215191a2595604.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论