2017-12-27 16 views
3

私はJava 8ストリームを勉強していますが、ラムダを理解するのはlambdas例えば(そして静的な)変数です。ほとんどのページは「効果的に最終的」であるという定義について話すだけなので、私はそれをオンラインで参照することはできないようです。なぜ「ラムダ式で使用される変数は最終的に有効であるか、最終的には最終的なものでなければならない」という警告がインスタンス変数では無視される

public class LambdaTest { 

    int instanceCounter = 0; 

    public void method() { 
     int localCounter = 0; 
     instanceCounter = 5; //Re-assign instance counter so it is no longer effectively final 

     Stream.of(1,2,3).forEach(elem -> instanceCounter++); //WHY DOES THE COMPILER NOT COMPLAIN HERE 
     Stream.of(1,2,3).forEach(elem -> localCounter++); //Does not compile because localCounter is not effectively final 
    } 
} 

答えて

4

我々はinstanceCounterが実際this.instanceCounterで、あなたが効果的に、最終的な、よくあるthisをキャプチャしていることを忘れがち。 については、が必要ですが、答えは明らかです。here

4

なぜローカル変数のコンパイルエラーですか?

実質的に最終的なルールは、グローバル変数ではなく、グローバル変数にのみ適用されます。そのため、グローバル変数を変更している最初のシナリオではコンパイルエラーはありません。

それはこのがそうコンパイル・エラーがない最後のローカル変数をキャプチャとして見ることができるインスタンス変数をキャプチャすることができます場合。

なぜこのような制限がありますか?

アクションでブックのJava-8は、この制限のために有効な説明があり、以下のように、それは行く:

ローカル変数はこれら 制限があり、なぜあなたはあなた自身に尋ねることができます。まず、インスタンス変数と ローカル変数が背後でどのように実装されているかに大きな違いがあります。インスタンス変数 はヒープに格納されますが、ローカル変数はスタックに格納されます。 ラムダがローカル変数に直接アクセスでき、ラムダがスレッドで使用された場合、ラムダを使用するスレッドは、 が割り当てを解除した後に変数 にアクセスしようとする可能性があります。したがって、Javaは元の変数にアクセスするのではなく、そのコピーへのアクセスとしてフリーのローカル変数 へのアクセスを実装します。

これはローカル変数が に割り当てられていても制限がない場合には違いはありません。第二に、この制限はまた、外部変数を変異させる典型的な命令型プログラミングパターンを避ける。

関連する問題