Java 8 クロージャは本当に一流の値ですか?それとも単なる構文糖衣ですか?
5 に答える
Java 8 クロージャー (「ラムダ」) は、単なる構文糖でもなければ、ファーストクラスの値でもないと言えます。
別の StackExchange の質問への回答で、シンタックス シュガーの問題に対処しました。
ラムダが「ファーストクラス」であるかどうかについては、実際には定義に依存しますが、ラムダは実際にはファーストクラスではないことを主張します。
ある意味で、ラムダは関数になりたいのですが、Java 8 は関数型を追加していません。代わりに、ラムダ式は関数型インターフェイスのインスタンスに変換されます。これにより、Java の型システムにわずかな変更を加えるだけでラムダを Java 8 に追加できるようになりました。変換後の結果は、他の参照型と同様の参照になります。実際、ラムダ式をパラメーターとして渡されたメソッドなどでラムダを使用することは、インターフェイスを介してメソッドを呼び出すことと区別がつきません。機能インターフェイス型のパラメーターを受け取るメソッドは、渡されたのがラムダ式なのか、その機能インターフェイスを実装するクラスのインスタンスなのかを判断できません。
ラムダがオブジェクトであるかどうかの詳細については、Lambda FAQ Answer to this question を参照してください。
ラムダはオブジェクトに変換されるため、オブジェクトのすべての特性を (文字通り) 継承します。特に、オブジェクト:
equals
、getClass
、hashCode
、notify
、 、などのさまざまな方法がtoString
ありますwait
- ID ハッシュ コードを持っている
synchronized
ブロックでロックできる==
and!=
andinstanceof
演算子を使用して比較できます
など。実際、これらはすべてラムダの使用目的とは無関係です。それらの動作は本質的に未定義です。これらのいずれかを使用するプログラムを作成すると、ある程度の結果が得られますが、結果はリリースごとに異なる場合があります (または、実行ごとに異なります!)。
これをより簡潔に言い直すと、Java では、オブジェクトにはIDがありますが、値 (特に、存在する場合の関数値) には ID の概念がありません。Java 8 には関数型がありません。代わりに、ラムダ式はオブジェクトに変換されるため、関数、特に ID とは関係のない多くの荷物があります。それは私には「ファーストクラス」のようには見えません。
2013-10-24 更新
数か月前に回答を投稿して以来、このトピックについてさらに考えてきました。技術的な観点から、私が上に書いたことはすべて正しいです。結論はおそらく、Java 8 ラムダが ( first-classとは対照的に)純粋な値ではないこととして、より正確に表現されます。ただし、不純だからといって、一流ではないというわけではありません。Wikipediaのファーストクラス関数の定義を考えてみましょう。簡単に言えば、関数をファーストクラスと見なすためにそこにリストされている基準は、次の能力です。
- 関数を引数として他の関数に渡す
- 他の関数から関数を返す
- 関数を変数に割り当てる
- 関数をデータ構造に格納する
- 関数を匿名にする
Java 8 ラムダは、これらの基準をすべて満たしています。そのため、彼らは一流のように見えます。
この記事では、特別なステータスを持たない関数名についても言及しています。代わりに、関数の名前は、型が関数型である単なる変数です。Java 8 ラムダは、この最後の基準を満たしていません。Java 8 には関数型がありません。機能的なインターフェースを備えています。これらは関数型のように効果的に使用されますが、関数型ではありません。型が関数型インターフェイスである参照がある場合、それがラムダなのか、匿名の内部クラスのインスタンスなのか、そのインターフェイスをたまたま実装する具象クラスのインスタンスなのかわかりません。
要約すると、Java 8 ラムダは、私が最初に考えていたよりも優れた関数です。それらは純粋なファーストクラスの関数ではありません。
はい、それらはファーストクラスの値です(または、Java 8がリリースされると...)
それらを引数として渡すことができるという意味で、それらを構成して高階関数を作成し、データ構造などに格納することができます。これらを幅広い関数型プログラミング手法に使用できるようになります。
このコンテキストでの「ファーストクラス」の意味のもう少しの定義についても参照してください。
私が見る限り、それはシンタックス シュガーですが、型推論、新しいパッケージjava.util.functions
、および内部クラスのセマンティックに加えて、ファースト クラスの値として表示されます。
外部コンテキストへの変数バインディングを伴う実際のクロージャーには、いくらかのオーバーヘッドがあります。Java 8 の実装は最適で、十分に純粋であると考えます。
少なくとも、単なる構文糖ではありません。
そして、これ以上最適な実装については知りません。
私にとって、Java 8 のラムダは単なる構文糖衣です。ファースト クラス シチズン ( http://en.wikipedia.org/wiki/First-class_function )として使用できないためです。各関数はオブジェクトにラップする必要があります。 SCALA のような純粋な一級関数を備えた言語。Java 8 クロージャーは、不変 (「実質的に最終的な」) 非ローカル変数のみをキャプチャできます。
これが構文糖である理由のより良い説明ですJava Lambdas and Closures