Java 8の型推論


30

Java 8 での新しいラムダ表記(たとえば、この記事を参照)の導入には、ある種の型推論が必要になりますか?

もしそうなら、新しい型システムはJava言語全体にどのような影響を与えますか?

回答:


47

ラチェットフリークの回答とコメントスレッドには、かなり誤った情報が含まれています。コメントが小さすぎるため、ここで回答します。また、これは結局答えなので、元の質問にも答えようとします。(ただし、私は型システムの専門家ではないことに注意してください。)

最初に、元の質問に対する短い答えは「はい」と「いいえ」です。はい、Java 8はJava 7よりもかなり多くの型推論を持ちます。いいえ、Java 8には「新しい」型システムはありません。

Java 8は依然として静的に型付けされ、クラスとインターフェースの間にはまだ二分されています。関数型などの新しい型はありません。ラムダのタイプは、基本的に単一の抽象メソッドを持つ通常のインターフェイスである「機能的インターフェイス」です。

インターフェイスは、デフォルトメソッドの形式でコードを持つことができますが、クラスの単一継承とインターフェイスの多重継承のモデルは同じままです。もちろん、デフォルトのメソッドが存在する場合のメソッド解決のルールなど、いくつかの調整がありますが、基本は変更されていません。

型の推論によって推論される型は、明示的に書き出すことができます。ラチェットフリークの例を使用するには、

Collections.<MyClass>sort(list, (a, b) -> { return a.order - b.order; });

基本的に砂糖です

Collections.<MyClass>sort(list,
    (Comparator<MyClass>)((MyClass a, MyClass b) -> { return a.order - b.order; }));

したがって、sparkleshyの「型推論には型システムの拡張は必要ありません」という文は基本的に正しいです。

しかし、構文糖に戻るために、ラムダ式は匿名の内部クラスの構文糖ではないというステートメントを繰り返しますラチェットフリークは、ラムダ式が匿名の内部クラスのインスタンス化に変換され、Sparkleshyがラムダ匿名の内部クラスの構文シュガーであることを再確認したが、これらのステートメントは間違っていると述べました。それらはおそらく古い情報に基づいています。初期のラムダ実装は、この方法でラムダを実装しましたが、状況は変わりました。

ラムダ式は、内部クラスと意味的に異なり、内部クラスとは異なる方法で実装されます。

ラムダ式は、いくつかの点で内部クラスと意味的に異なります。ラムダ式を評価するたびに新しいインスタンスを作成する必要はありません。また、キャプチャのセマンティクスも異なります。たとえば、これは異なる方法でキャプチャます。内部クラスでは、これは内部クラスのインスタンスですが、ラムダでは、これは包含インスタンスです。以下を考慮してください。

public class CaptureThis {
    void a(Runnable r) { r.run(); }

    void b() {
        a(new Runnable() { public void run() { System.out.println(this); }});
        a(() -> System.out.println(this));
    }

    public String toString() { return "outer"; }

    public static void main(String[] args) { new CaptureThis().b(); }
}

最近のJDK 8 ラムダビルドb69を使用しました)では、出力は次のようになります。

CaptureThis$1@113de03
outer

さらに、ラムダ式は、内部クラスとはまったく異なる方法で実装されます。逆アセンブルされた出力を比較すると、内部クラスコードが作成に直接コンパイルされ、CaptureThis $ 1のコンストラクターが呼び出されますが、ラムダ式はRunnableを取得するinvokedynamic命令にコンパイルされます。この仕組みと理由の詳細については、Brian GoetzのJavaOne 2012トークLambda:A Peek Under the Hoodをご覧ください。


2
「彼らは異なり、これを取り込む内部クラスでは、これは内部クラスのインスタンスである、ラムダでは、これは親インスタンスであるのに対し、次の点を考慮。。」まだすべてを置き換えることにより、糖衣構文で行うことができるthisMyClass.this
ラチェットフリーク

4
アセンブラーを超えるものはすべて(場合によってはそれも)、間違いなく構文糖衣です。しかし、ラムダは内部クラスの構文糖衣ではありません(これ以上)。それらは似たような目的を果たし、いくつかの類似点を持っていますが、内部では(明らかに)異なっています。
ヨアヒムザウアー

1
「ラムダ式は、内部クラスと意味的に異なり、内部クラスとは異なる方法で実装されます。」:非常に良い説明(+1)をありがとう。ラムダが特別な匿名クラスの構文糖として実装されていないのはなぜか、言い換えると、新しいセマンティクスによってもたらされる余分な複雑さの利点は何ですか?匿名の内部クラスでは解決できない、これはどのような問題を解決しますか?(しかし、私はまだあなたが投稿したリンクを見る必要があります、多分私はそこに答えを見つけるでしょう。)
ジョルジオ

1
@Joachim Sauer:構文糖は既存のセマンティクスの新しい構文だと思います。新しいセマンティクスが導入されたとき、構文糖について話すことはできないと思います。この意味で、アセンブラーを超えたものはすべて構文糖であると主張できるとは思いません。
ジョルジオ

3
@Giorgio:ラムダが匿名の内部クラスの単なる構文糖ではない理由については、これについて大きな議論があったことが判明しました。Brian Goetzからのこのメールは、決定を要約しています:mail.openjdk.java.net/pipermail/lambda-dev/2011-August/…。TL; DRにより、将来の進化に向けて扉が開かれたままになり、今日はパフォーマンスが向上しています。Goetzは実際に関連する質問に答えています、ラムダオブジェクトですか?しかし、答えが「いいえ」である場合、またはたぶんそれは、内部クラスの砂糖ではないことを意味します。
スチュアートマークス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.