実質的にfinal
Javaのラムダ式では実質的にfinalなローカル変数にアクセスできるらしい。
参考書には「finalで修飾されていなくても変更されない変数」とあった。
どういうことか
「final付いていないけど宣言時から一切変更無いからつまりfinalと同じだよね!」ってこと
この場合、ローカル変数i
は実質的finalだけど、
LambdaStudy.java
public class LambdaStudy {
public static void main(String[] args) {
int i = 10;
Calculate c = x -> x + i;
System.out.println(c.calc(20));//30
}
}
interface Calculate {
public int calc(int x);
}
この場合はインクリメントでi
の値を変えてしまっているので、実質的finalでは無くなり、コンパイルエラーとなってしまう。
LambdaStudy.java
public class LambdaStudy {
public static void main(String[] args) {
int i = 10;
i++;
Calculate c = x -> x + i;//Local variable i defined in an enclosing scope must be final or effectively final
System.out.println(c.calc(20));
}
}
interface Calculate {
public int calc(int x);
}
#参照型ではどうか
参照型であっても変わらない。
この場合、sb.append("d")
は変数sb
の参照先のオブジェクトに変更を与えているだけで変数sb
それ自体を変更している訳では無いのでsb
は実質的finalとなり実行できる。
LambdaStudy.java
public class LambdaStudy {
public static void main(String[] args) {
int i = 10;
StringBuilder sb = new StringBuilder("abc");
sb.append("d");
Calculate c = x -> {
System.out.println(sb.toString());//abcd
return x + i;
};
System.out.println(c.calc(20));//30
}
}
interface Calculate {
public int calc(int x);
}
sb
に再代入したらsb
の参照先が変わってしまうので実質的finalでは無くなってしまう。(コンパイルエラー)
LambdaStudy.java
public class LambdaStudy {
public static void main(String[] args) {
int i = 10;
StringBuilder sb = new StringBuilder("abc");
sb.append("d");
sb = new StringBuilder("efg");
Calculate c = x -> {
System.out.println(sb.toString());//Local variable sb defined in an enclosing scope must be final or effectively final
return x + i;
};
System.out.println(c.calc(20));
}
}
interface Calculate {
public int calc(int x);
}
#まとめ
実質的finalな変数とは**「変数宣言時から一切変更がない変数」**のことである。