local variables must be final or effectively final の原因と直し方
ラムダが参照するローカル変数は再代入できません。配列で回避する定石も扱います。
エラーメッセージの読み方
Main.java:7: error: local variables referenced from a lambda expression must be final or effectively final
Main.java- ファイル名
7- 行番号 — javacが異常に気づいた位置。原因の行とは限りません
error- 種別 — コンパイルエラー。実行まで到達しません
local variables referenced from a lambda expression must be final or effectively final- 内容 — javacが期待していたもの、または見つけられなかったもの
このエラーが出る典型パターン
パターン1
1 import java.util.List; 2 3 public class Main { 4 public static void main(String[] args) { 5 int count = 0; 6 count = 1; ^ 7 List.of(1, 2, 3).forEach(n -> System.out.println(n + count)); 8 } 9 }
Main.java:7: error: local variables referenced from a lambda expression must be final or effectively final
ラムダが参照するローカル変数は再代入できません。ラムダより前であっても、一度でも代入し直すと実質finalではなくなります。
直し方: count = 1; を (空) にします。
広告
広告スロット(未設定)
パターン2
1 import java.util.List; 2 3 public class Main { 4 public static void main(String[] args) { 5 int[] sum = {0}; 6 List.of(1, 2, 3).forEach(n -> sum = new int[]{n}); ^ 7 System.out.println(sum[0]); 8 } 9 }
Main.java:6: error: local variables referenced from a lambda expression must be final or effectively final
配列変数そのものは再代入していないので、要素の書き換えは許されます。実質finalの回避策として使われます。
直し方: sum = new int[]{n} を sum[0] += n にします。
パターン3
1 import java.util.function.Function; 2 3 public class Main { 4 public static void main(String[] args) { 5 Function<Integer, Integer> f = n => n * 2; ^ 6 System.out.println(f.apply(3)); 7 } 8 }
Main.java:5: error: illegal start of expression
Javaのラムダの矢印は -> です。=> は他の言語の記法で、Javaでは通りません。
直し方: => を -> にします。
よくある誤解
配列で回避するのは常套手段ですが、そうしたくなったら設計を疑う合図でもあります。
まとめ
local variables must be final or effectively finalは上級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。