2017-02-04 3 views
-2

に取り込むラムダ後比較ラムダは、C#コード与えるC#やJavaの

Before lambda, x = 10 
The successor of 10 is 11 
After lambda, x = 11 

を、xの値は、ラムダ作用によって影響されるので、この関数の引数を参照渡しに渡すのと同じです。

のは、Javaと比較してみましょう:

interface Inc 
{ 
    int Increment(); 
} 

int x = 10; 
Inc next =() -> { return ++x; }; 

System.out.println("Before lambda, x = " + x); 
System.out.println("The successor of " + x + " is " + next.Increment()); // ERROR: local variables referenced from a lambda expression must be final or effectively final 
System.out.println("After lambda, x = " + x + "\n"); 

私はこれにラムダを変更する場合:

Inc next =() -> { return x+1; }; 

出力は次のようになります。ラムダ後

Before lambda, x = 10 
The successor of 10 is 11 
After lambda, x = 10 

、xの値ラムダアクションの影響を受けないので、これは引数に関数の引数を渡すのと同じです。

Javaがキャプチャされた変数を変更するのを防ぐ技術的な理由は何ですか?

私は、エラーメッセージが言うことを知っている:

«ラムダ式から参照ローカル変数は、最終的または効果的に最終でなければなりません»しかし、これは私には十分ではありません。その背後にある技術的な理由は何ですか?

Javaでキャプチャされた変数がラムダによって変更される可能性がある場合はどうなりますか?

ありがとうございます。

答えて

0

JavaおよびJVMは、ローカル変数への参照をサポートしていません。コンパイラが行うことができるのは、変数を参照に変換することですが、そうではありません。

このようにコードを翻訳することができます。

int[] x = { 10 }; 
IntSupplier next =() -> { return ++x[0]; }; 

System.out.println("Before lambda, x = " + x); 
System.out.println("The successor of " + x + " is " + next.getAsInt()); // 
System.out.println("After lambda, x = " + x + "\n"); 

本当にこれが必要な場合は、コードを自分で変更することができます。

BTW関数型プログラミングの重要な機能の1つは、可能な限り純粋な関数を使用することです。純粋な関数には副作用がありません。 Javaには純粋な機能を実装する方法はありませんが、微妙な副作用をもたらす方法を追加することは、機能的な構造を追加することと一貫していないように見えます。

+0

私は変数が値によって捕捉されているので、これは副作用とは関係ないと思うので、ラムダの中に変数のコピーがあります。 –

+1

@ArnbjorgJohansen正確には、変数の*コピー*があります。つまり、オリジナルを更新できません。誤ってコピーを更新するとオリジナルを更新するのを防ぐために、言語設計者は変数を*(効果的に)* final(不変)にすることを決定したので、間違いを犯すことはできません。 ---うーん、私の答えは「それの背後にある技術的な理由は何ですか?」* – Andreas

+0

@ArnbjorgJohansen状態の変化は副作用です。 –