1. ホーム
  2. java

[解決済み] ラムダ式から参照されるローカル変数は、final または effectively final でなければならない。

2022-03-03 05:59:32

質問

私はJavaFX 8プログラム(JavaFXPortsクロスプラットフォーム用)を持っていて、私が望むことを行うためにかなりフレームされていますが、1つのステップが不足していました。このプログラムは、テキストファイルを読み、行を数えてランダムな範囲を確立し、その範囲から乱数を選び、その行を読み込んで表示するものです。

The error is: local variables referenced from a lambda expression must be final or effectively final
        button.setOnAction(e -> l.setText(readln2));

私はjavaに少し新しいですが、私は次のランダムな行を表示するためにLambdaを使用するかどうかであるようだ Label l は、私の button.setOnAction(e -> l.setText(readln2)); の行は、静的な値を期待しています。

画面上のボタンを押すたびに、var readln2 の次の値が表示されるようにするには、どのように調整したらよいでしょうか?

事前にありがとうございます。以下は私のコードです。

String readln2 = null;
in = new BufferedReader(new FileReader("/temp/mantra.txt"));
long linecnt = in.lines().count();
int linenum = rand1.nextInt((int) (linecnt - Low)) + Low;
try {
    //open a bufferedReader to file 
    in = new BufferedReader(new FileReader("/temp/mantra.txt"));

    while (linenum > 0) {
        //read the next line until the specific line is found
        readln2 = in.readLine();
        linenum--;
    }

    in.close();
} catch (IOException e) {
    System.out.println("There was a problem:" + e);
}

Button button = new Button("Click the Button");
button.setOnAction(e -> l.setText(readln2));
//  error: local variables referenced from a lambda expression must be final or effectively final

解決方法は?

の値をコピーすればいいだけです。 readln2final 変数を使用します。

    final String labelText = readln2 ;
    Button button = new Button("Click the Button");
    button.setOnAction(e -> l.setText(labelText));

毎回新しいランダムな行を取得したい場合は、対象の行をキャッシュし、イベントハンドラでランダムな行を選択することができます。

Button button = new Button("Click the button");
Label l = new Label();
try {
    List<String> lines = Files.lines(Paths.get("/temp/mantra.txt"))
        .skip(low)
        .limit(high - low)
        .collect(Collectors.toList());
    Random rng = new Random();
    button.setOnAction(evt -> l.setText(lines.get(rng.nextInt(lines.size()))));
} catch (IOException exc) {
    exc.printStackTrace();
}
// ...

あるいは、イベントハンドラでファイルを再読み込みすることもできます。前者は(はるかに)高速ですが、大量のメモリを消費します。後者はファイルの内容をメモリに保存せず、ボタンが押されるたびにファイルを読み込むので、UIが応答しなくなる可能性があります。

ラムダ式の内部からアクセスできるローカル変数は次のいずれかです。 final (宣言 final または、quot;effective final"(基本的に、他のコードに変更を加えることなくfinalにできることを意味します)。

あなたのコードがコンパイルに失敗するのは readln2 は(ループの中で)複数回値が代入されるため、宣言できません。 final . したがって、ラムダ式でアクセスすることはできません。上のコードでは、ラムダ式でアクセスされる変数は l , lines および rng これらはすべて一度だけ値が割り当てられるので、実質的にfinal`です。(それらをfinalと宣言しても、コードはコンパイルされます)。