ラムダ式は、単一のメソッドを持つ匿名の内部クラス以上のものですか?


40

Java 8には、待望のラムダ式に関する新しい誇大宣伝があります。3日ごとに、彼らがいかにクールであるかについての別の記事が表示されます。

私が理解している限り、ラムダ式は(少なくともバイトコードレベルで)単一メソッドを持つ匿名内部クラスにすぎません。これに加えて、別の優れた機能があります-型推論ですが、これと同等の機能は、あるレベルのジェネリックで実現できると信じています(もちろん、ラムダ式のようなきちんとした方法ではありません)。

これを知っていると、ラムダ式は単なるJavaの構文糖衣以上のものをもたらすでしょうか?現在の言語機能では構築できないラムダ式を使用して、より強力で柔軟なクラスやその他のオブジェクト指向の構造を作成できますか?


30
言語がチューリング完全である場合追加されたすべての機能は、理論的には「構文糖」と説明できます。
フィリップ

34
@フィリップ:それは間違っています。構文糖の定義的な特徴は、脱糖が純粋にローカルであり、プログラムのグローバル構造を変更しないことです。ローカル変換だけでは実装できない機能がたくさんあります。たとえば、Javaと同一であるが適切なテールコールを使用する仮想言語を使用する場合、プログラム全体をグローバルに変換しない限り、テールコールをデピュアしてJavaを「純粋」にすることはできません。
ヨルグWミットタグ

2
@Philipp:残念ながら、コメントに対する賛成票は1つしかありません。そうでなければ、Joergのコメントに1000回賛成票を投じることになります。いいえ、すべての機能が構文糖衣として説明できるのは間違っています。構文糖は新しいセマンティクスを追加しません。実際、提案されたJavaラムダは、セマンティクスが異なるため、特別な匿名内部クラスの構文糖衣ではありません。
ジョルジオ

1
@Giorgio:そして、どのようなセマンティクスがありますか?
user102008

2
@Giorgio:はい、しかし、の変換thisには、OuterClass.this匿名クラスにラムダ式をデsugaringのプロセスの一部です。
user102008

回答:


47

TL; DR:それはだが、主にシンタックスシュガーが、そのよりよいの構文は中括弧と括弧の無限の、判読できない行で終了するために使用することを実用的なものをたくさん作ります。

ラムダはJavaよりもずっと古いので、実際には逆です。単一のメソッドを持つ匿名の内部クラスは、(最も)Javaがラムダに近づいたものです。これはしばらくの間は「十分」だった近似値ですが、非常に厄介な構文を持っています。

表面的には、Java 8のラムダは構文上の砂糖以上のものではないように見えますが、表面の下を見ると、多くの興味深い抽象化が見られます。たとえば、JVM仕様はラムダを「true」オブジェクトとはまったく異なる方法で処理し、オブジェクトをオブジェクトのように扱うことができますが、JVMはそれらを実装する必要はありません。

しかし、その技術的なトリックはすべて興味深いものであり(JVMで将来の最適化が可能になるためです!)、本当の利点は構文糖の部分だけです。

読みやすいもの:

myCollection.map(new Mapper<String,String>() {
  public String map(String input) {
    return new StringBuilder(input).reverse().toString();
  }
});

または:

myCollection.map(element -> new StringBuilder(element).reverse().toString());

または(ラムダの代わりにメソッドハンドルを使用):

myCollection.map(String::toUpperCase);

これまで5行のコード(うち3行はまったくつまらない)だった簡潔な方法で最終的に表現できるという事実は、実際的な実際の可能性ではなく)現実の変化をもたらします。


1
私は構文の糖化部分に完全に同意します。私の質問は、ラムダ式でのみ可能な新しいオブジェクト指向の構造に関するものでした。結局、Javaはオブジェクト指向言語です。ジェネリックと比較して、そして彼らがどのようにJavaで多くの柔軟性を購入したか、それらなしでは達成できない柔軟性を考えてみてください。
m3th0dman

7
@ m3th0dman:実際にジェネリックは新しい機能を追加しませんでした。A Listは任意のオブジェクトを保持でき、List<String>文字列を「のみ」保持できます。ジェネリックは、権限の追加ではなく、制限(および制限を形式化するオプション!)を追加しました。Java 1.1以降、ほとんどすべてが構文糖衣です。それは必ずしも悪いことではありません。
ヨアヒムザウアー

3
@ m3th0dman:ジェネリックは実際には新しい機能を追加しませんでした。Javaでは、これらは単なる構文上の糖だからです。A List<String>は、いくつかの戻り値の周りListString追加されたキャストです。それにもかかわらず、それらは非常に有用であり、言語を書くのがはるかに便利になりました。ラムダも同様です。
Jan Hudec

3
実際、それは単なる構文上の砂糖以上のものです。多くの機能は、invokedynamicバイトコードとType推論システムのかなりの進歩の使用により、JVMのファーストクラスの市民として実装されます。匿名の内部クラスとして実装されていません。
マーティンヴェルブルク

1
@JanHudec:コンパイラーは実際にそれらを尊重しているため、構文上の砂糖よりもわずかに多くなっています。ランタイムはそれが本当、それらについて気にしません。
ヨアヒムザウアー

14

Javaの場合、はい、匿名の内部クラスを作成するより良い方法にすぎません。これは、バイトコードのすべてのビットが特定のクラス内に存在しなければならないというJavaの基本的な決定によるものです。

しかし、それはラムダ式が本当に意味するものではありません。それらがバンドワゴンのゆがみではなくネイティブの概念である形式主義では、ラムダは基本的な構成要素です。それらの構文とそれらに対する人々の態度は非常に異なっています。コンピュータプログラムの構造と解釈のラムダから純粋に作成された匿名の再帰関数の例は、計算の概念全体を変更することができます。(ただし、プログラミングの学習方法は、主流のサクセスストーリーになるためには難解であるにすぎないことは確かです。)


1
すべてがラムダの観点から実装できることを知ることは非常に有益であり、私の意見では「難解」ではありません。(ただし、ほとんどの「コーダー」は興味深いCS理論を気にしていないと思います。)それは、ラムダが特別であることを意味しません。それは、ラムダが普遍的な構造の一種であることを意味します。SKIコンビネーターなど、他にもあります。ラムダは機能的なパラダイムの基本的な構成要素ですが、別のパラダイムでは他の何かが基本になる場合があります。
user102008

「時流ジャンプのゆがみ」の+1:一部の言語が他の一般的な言語を模倣するように変化し続ける理由と、プログラマーがそれを我慢する理由をよく疑問に思います。私はラムダが好きで、Scala、Lisp、Haskellでよく使用しますが、JavaやC ++では、他の言語で人気が出てきたという理由だけで、言語に後付けされたように感じます。
ジョルジオ

2

はい、それは単なる構文上のシュガーです。ラムダを書くところならどこでも、その式を1つのメソッドで匿名の内部クラス式として書き直すことができ、クラスはラムダのコンテキストに対して推論された機能的インターフェースを実装します意味的にはまったく同じです。また、ラムダ式を匿名クラス式に置き換えるだけで、他の式やコード行を変更せずにこれを行うことができます。


1
なぜ投票するのですか?私が言ったことは完全に正しいです
-user102008

あなたが書いたものはJavaラムダの合理的な提案のように聞こえますが、この提案は別のものを支持して破棄されました(doanduyhai.wordpress.com/2012/07/12/…)。
ジョルジオ

1
@Giorgio:私は何も「提案」していません。正確に、あなたが私が言ったことに同意しませんか?はい、式の内部は異なって見えます。たとえば、メソッドを追加し、はい、thisに変換する必要がありOuterClass.thisます。それは私が言ったことと矛盾しません-すべてのラムダ、その式の外に何も変更することなく、意味的に同等の匿名クラス式に変換できます。私は内部が変わらないとは言わなかった。
user102008

3
あなたが言ったことは間違っています。lambdaとanonの内部クラスのセマンティクスはまったく同じではありません(ただし、類似しています)。私の頭の意味の意味の上から、この変化。そして、非内部クラスは常にオブジェクトの新しいインスタンスになりますが、ラムダはそうでない場合があります。
スチュアートマークス

1
@StuartMarks:いいえ、あなたは私の答えを読んでいませんでした。私は彼らのそれぞれが他の人がすることをすべてできるとは言わなかった。ラムダには、意味的に同じである同等の匿名クラスがあると言いました。すでにコメントで述べたようにthis、ラムダは構文糖衣の一部であり、セマンティクスの違いではありません。実装の違いについては、実装!=セマンティクスです。オブジェクトIDの違いについて。オブジェクトの同一性は、ラムダの機能に非常に正接しています。とにかくラムダ/アノンクラスのオブジェクトIDをチェックする人はいません。
-user102008

1

ヨアヒム・ザウアーはすでにあなたの質問に答えてくれましたが、私が重要だと思うことだけを示唆していました。ラムダはクラスではないため、そのようにコンパイルされません。すべての匿名内部クラスは、ClassLoaderによってロードされる必要がある.classファイルの作成をもたらします。そのため、代わりにLambdasを使用すると、コードがより美しくなるだけでなく、コンパイルされたコードのサイズ、ClassLoaderのメモリフットプリント、およびハードドライブからビットを転送するのにかかる時間が削減されます。


-1

いいえそうではありません。

別の言い方をすると、ラムダは非オブジェクト指向ですが、匿名クラスまたは私の好みである内部クラスがオブジェクト指向の方法で達成するのと同じことを達成するための簡潔な方法です。


1
関数型プログラミングは、オブジェクト指向プログラミングと完全に直交することができます(ScalaおよびF#を参照)。これは、原則として関数型プログラミングを単に嫌う人の意見のように読みます。
KChaloux 14年

1
@KChaloux-関数型プログラミング嫌いではありません。答えは、ハンマードライバーよりもハンマーとドライバーを好む人によって書かれています。オブジェクト指向プログラミングは、関数型プログラミングと同様に優れたパラダイムです。私の言語の好みは、その意図を明確にすることです。ラムダ私はJavaの本来のオブジェクト指向の性質を濁っています。Javaは関数型言語として設計されていません。人間は最善の仕事をするために構造が必要です。
グイドアンセルミ14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.