Apa itu 'tipe SAM' di Jawa?

133

Membaca di spec Java-8, saya terus melihat referensi ke 'tipe SAM'. Saya belum dapat menemukan penjelasan yang jelas tentang apa ini.

Apa itu tipe SAM dan apa contoh skenario kapan seseorang bisa digunakan?

Cody
sumber
4
Lihat cr.openjdk.java.net/~briangoetz/lambda/lambda-state-3.html (yang saya temukan setelah pencarian tunggal, yang membawa saya ke pertanyaan SO lainnya).
Jon Skeet
2
Tolong jangan merujuk orang ke informasi yang ketinggalan zaman. Pencarian yang sedikit lebih lama akan membawa Anda ke versi yang lebih baru: cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html , yang sudah berusia 18 bulan dan sekarang sudah ketinggalan zaman di banyak tempat Pertanyaan OP dijawab di lambdafaq.org/what-is-a-functional-interface , satu halaman di FAQ yang saya coba untuk tetap up to date dalam apa yang sampai saat ini perkembangan bahasa dan API yang berubah dengan cepat.
Maurice Naftalin
1
@MauriceNaftalin Anda juga bisa menghubungkan tautan Java , yang selalu diperbarui oleh tim pengembang.
Brian
1
Istilah saat ini adalah "antarmuka fungsional".
berita baru
1
@MauriceNaftalin: Maaf, ketinggalan yang itu. Pasti akan terhubung dengan itu jika saya menemukan itu.
Jon Skeet

Jawaban:

142

Untuk meringkas link Jon diposting 1 dalam kasus itu pernah turun, "SAM" singkatan dari "metode abstrak tunggal", dan "SAM-tipe" mengacu pada interface seperti Runnable, Callable, dll ekspresi Lambda, fitur baru di Jawa 8, yang dianggap sebagai tipe SAM dan dapat secara bebas dikonversi ke mereka.

Misalnya, dengan antarmuka seperti ini:

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

Anda dapat mendeklarasikan Callableekspresi lambda yang menggunakan seperti ini:

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

Ekspresi Lambda dalam konteks ini sebagian besar hanya gula sintaksis. Mereka terlihat lebih baik dalam kode daripada kelas anonim dan kurang membatasi penamaan metode. Ambil contoh ini dari tautan:

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);

Ini menciptakan Comparatorpenggunaan metode tertentu yang tidak berbagi nama yang sama denganComparator.compare , sehingga Anda tidak harus mengikuti penamaan antarmuka metode dan Anda dapat memiliki beberapa pembandingan perbandingan dalam suatu kelas, kemudian membuat pembanding dengan cepat ekspresi lambda.

Lebih dalam ...

Pada level yang lebih dalam, Java mengimplementasikan ini menggunakan invokedynamicinstruksi bytecode yang ditambahkan di Java 7. Saya katakan sebelumnya bahwa mendeklarasikan Lambda menciptakan instance Callableatau Comparablemirip dengan kelas anonim, tetapi itu tidak sepenuhnya benar. Sebagai gantinya, pertama kali invokedynamicdipanggil, ia menciptakan fungsi pengendali Lambda menggunakan LambdaMetafactory.metafactorymetode , kemudian menggunakan contoh ini di-cache dalam doa selanjutnya dari Lambda. Info lebih lanjut dapat ditemukan dalam jawaban ini .

Pendekatan ini kompleks dan bahkan termasuk kode yang dapat membaca nilai-nilai primitif dan referensi langsung dari memori tumpukan untuk masuk ke kode Lambda Anda (misalnya untuk berkeliling perlu mengalokasikan Object[]array untuk memanggil Lambda Anda), tetapi memungkinkan iterasi implementasi Lambda di masa mendatang. untuk mengganti implementasi lama tanpa harus khawatir tentang kompatibilitas bytecode. Jika para insinyur di Oracle mengubah implementasi Lambda yang mendasari dalam versi JVM yang lebih baru, Lambdas yang dikompilasi pada JVM yang lebih lama akan secara otomatis menggunakan implementasi yang lebih baru tanpa perubahan apa pun pada bagian pengembang.


1 Sintaks pada tautan sudah kedaluwarsa. Lihatlah Lambda Expressions Java Trail untuk melihat sintaks saat ini.

Brian
sumber