151

Java-8仕様を読んでいると、「SAMタイプ」への参照が引き続き見られます。これが何であるかの明確な説明を見つけることができませんでした。

SAM タイプとは何ですか? また、SAM が使用されるシナリオの例は何ですか?

4

1 に答える 1

171

ダウンした場合に備えてJon が投稿したリンク1を要約すると、「SAM」は「単一の抽象メソッド」を表し、「SAM タイプ」は 、 などRunnableのインターフェースを指しますCallable。Java 8 の新機能であるラムダ式は、 SAM タイプと見なされ、自由に変換できます。

たとえば、次のようなインターフェイスを使用します。

public interface Callable<T> {
    public T call();
}

Callable次のようにラムダ式を使用して宣言できます。

Callable<String> strCallable = () -> "Hello world!";
System.out.println(strCallable.call()); // prints "Hello world!"

このコンテキストでのラムダ式は、ほとんどが単なる構文糖衣です。これらは、匿名クラスよりもコードで見栄えがよく、メソッドの命名に関する制限が少なくなります。リンクからこの例を取得します。

class Person { 
    private final String name;
    private final int age;

    public static int compareByAge(Person a, Person b) { ... }

    public static int compareByName(Person a, Person b) { ... }
}

Person[] people = ...
Arrays.sort(people, Person::compareByAge);

これにより、Comparatorと同じ名前を共有しない特定のメソッドを使用してが作成されます。これにより、Comparator.compareメソッドのインターフェース命名に従う必要がなくなり、クラスで複数の比較オーバーライドを使用して、その場でコンパレーターを作成することができます。ラムダ式。

もっと深く...

より深いレベルでは、Javainvokedynamicは Java 7 で追加されたバイトコード命令を使用してこれらを実装します。前に、Lambda を宣言すると匿名クラスのインスタンスCallableまたは類似のインスタンスが作成されると述べましたが、厳密にはそうではありません。代わりに、 が初めて呼び出されたときに、メソッドを使用して Lambda 関数ハンドラーを作成し、その後の Lambda の呼び出しでこのキャッシュされたインスタンスを使用します。詳細については、この回答を参照してください。ComparableinvokedynamicLambdaMetafactory.metafactory

このアプローチは複雑で、プリミティブ値と参照をスタック メモリから直接読み取って Lambda コードに渡すことができるコード (たとえば、Object[]Lambda を呼び出すために配列を割り当てる必要があることを回避するため) も含まれますが、Lambda 実装の将来の反復を可能にします。バイトコードの互換性を心配することなく、古い実装を置き換えることができます。Oracle のエンジニアが新しいバージョンの JVM で基礎となる Lambda 実装を変更した場合、古い JVM でコンパイルされた Lambda は、開発者側で変更を加えることなく、新しい実装を自動的に使用します。


1リンクの構文が古くなっています。Lambda Expressions Java Trailを見て、現在の構文を確認してください。

于 2013-07-28T22:37:41.523 に答える