2016-12-15 8 views
1

ローカル変数とそれに対応できないようなラムダファンクションについて、奇妙な問題が発生しました。私は「外側のスコープで定義されたローカル変数ACCが最終的または効果的に最終でなければなりません」というエラー・メッセージが出続けるJavaでのローカル変数+ラムダ関数のエラー

私のコードは次のようになります。

Accumulator acc = new Accumulator(0, 0); 
stream.reduce(0, (sum, value) -> { 
    acc = new Accumulator(sum + value, acc.getB()+1); 
    return sum + value; 
}); 

をだから、あなたが見ることができるように、私は整数の流れを減らそうとしていて、還元プロセスからのものだけではなく2つの値を保持しています。小さなヘルパークラスAccumulatorにこれらの値を保存しようとしていますが、これにはfinal int afinal int bが格納されています。しかし、には届かないstream.reduceのようです。

他のラムダ関数を含む他の部分では、同様のコード構造がうまく動作します(ローカル変数を宣言し、ラムダ関数内でそれらを変更する)ので、何をすべきか分かりません。

例(streamはもちろん、初期化されます):

ArrayList<StudentRecord> studentList = new ArrayList<StudentRecord>(); 
stream.forEach(student -> { 
    studentList.add(student); 
}); 

ヘルプをいただければ幸いです、 よろしく

+0

エラーメッセージは、何が間違っているかを正確に伝えています: 'acc'は' final'と宣言されていません。質問はなんですか? –

+0

[検索前に検索してください](/検索?q =%5Bjava%5D +ローカル+変数+定義+ in + an +囲み+スコープ+ must + be + final +または+ effective + final) ](/ help/searching)をクリックします。 –

+0

他のコードも投稿すれば、その違いを教えていただけます。そうでなければ私たちがここで行うことはありません。 – HopefullyHelpful

答えて

2

コメントで説明したように、ラムダ式内のローカル変数に代入することはできません。しかし、あなたが望む出力を生成する方法をreduceと呼ぶ方法があります。例えば

:(あなたのStreamが平行である場合を除く)

Stream<Integer> stream = Stream.of (1,2,3,4,5); 
Accumulator result = 
    stream.reduce(new Accumulator(0,0), // initial value 
        (acc, i) -> {acc.a += i;acc.b++; return acc;}, // add current value to 
                   // the accumulator 
        (acc1, acc2) -> new Accumulator (acc1.a+acc2.a,acc1.b+acc2.b)); // combine two accumulators 
System.out.println ("sum = " + result.a); 
System.out.println ("count = " + result.b); 

これはほんの一Accumulatorのインスタンスを生成します。出力Accumulatorには、合計がacc.a、要素数がacc.bになります。

出力:

sum = 15 
count = 5 

私はこれが唯一の教育目的のためであると仮定しています。そうでない場合は、合計、要素の数、その他のプロパティ(最小、最大、平均)を計算するIntStreamsummaryStatistics()を使用する方が理にかなっています。

+0

はい、これは教育目的のためであり、プロセス内でAccumulatorのようなクラスを使用することさえも勧められませんでした。私はちょうどそれを実装したい、立ち往生し、理由を知りたいと思った。あなたのスニペットをありがとう、それは私を非常に助けました! – Daniel

1

変数をfinalとして宣言することはできませんが、それは再割り当てされてはならないので、事実上最終的です。 コードの3行目で、変数を再割り当てします。これは不可能です。

他のコードでも同様のことが既に成功していると言えば、これは不可能だと思います。おそらくあなたは変数が参照するオブジェクトを変更しましたが、変数自体は変更しませんでした。

+0

ありがとうございました。私は、「効果的に最終的に」とは何かを完全には確信していなかった。 – Daniel

+0

あなたの答えは間違いありませんが、今後変更される可能性がある仕様の詳細を記述しているため、Java仕様やドキュメントへの参照なしにこの種の要求を行うことは避けられます。それ以外の場合は、この動作が観察されている場所で使用している現在のJavaバージョンを含めてください。あるいは、最初にさまざまな例であなたの主張が真実であることを確認し、答えにそれらを含めることができます。 1つは、次のJavaバージョンでは変更が予定されているので、この回答は将来の訪問者を混乱させることです。 – HopefullyHelpful

+0

@HopefullyHelpful lamdasを使用しているので、私たちはもちろんJava 8について話しています。実際、Java 8より前の匿名の内部クラスでは、finalとして明示的に宣言された変数しか使用できませんでした(Java 7以前Java 7へ)。 –