Karena Java8 baru-baru ini dirilis dan ekspresi lambda barunya terlihat sangat keren, saya bertanya-tanya apakah ini berarti matinya kelas Anonymous yang dulu biasa kita alami.
Saya telah meneliti sedikit tentang ini dan menemukan beberapa contoh keren tentang bagaimana ekspresi Lambda akan secara sistematis menggantikan kelas-kelas tersebut, seperti metode sortir Collection, yang digunakan untuk mendapatkan contoh Anonymous dari Pembanding untuk melakukan pengurutan:
Collections.sort(personList, new Comparator<Person>(){
public int compare(Person p1, Person p2){
return p1.firstName.compareTo(p2.firstName);
}
});
Sekarang dapat dilakukan menggunakan Lambdas:
Collections.sort(personList, (Person p1, Person p2) -> p1.firstName.compareTo(p2.firstName));
Dan terlihat sangat ringkas. Jadi pertanyaan saya adalah, apakah ada alasan untuk tetap menggunakan kelas-kelas tersebut di Java8 daripada Lambdas?
EDIT
Pertanyaan yang sama tetapi dalam arah yang berlawanan, apa manfaat menggunakan Lambdas daripada kelas Anonim, karena Lambdas hanya dapat digunakan dengan antarmuka metode tunggal, apakah fitur baru ini hanya pintasan yang hanya digunakan dalam beberapa kasus atau apakah itu benar-benar berguna?
sumber
Comparator.comparing(Person::getFirstName)
jikagetFirstName()
akan menjadi metode yang kembalifirstName
.Jawaban:
Kelas dalam anonim (AIC) dapat digunakan untuk membuat subkelas dari kelas abstrak atau kelas konkret. AIC juga dapat memberikan implementasi konkret dari sebuah antarmuka, termasuk penambahan status (bidang). Sebuah instance dari AIC dapat dirujuk menggunakan
this
dalam badan metodenya, sehingga metode lebih lanjut dapat dipanggil, statusnya dapat dimutasi dari waktu ke waktu, dll. Tak satu pun dari ini berlaku untuk lambda.Saya menduga bahwa sebagian besar penggunaan AIC adalah untuk menyediakan implementasi stateless dari fungsi tunggal sehingga dapat diganti dengan ekspresi lambda, tetapi ada penggunaan AIC lain yang tidak dapat digunakan lambda. AIC akan tetap ada.
MEMPERBARUI
Perbedaan lain antara AIC dan ekspresi lambda adalah AIC memperkenalkan ruang lingkup baru. Yaitu, nama diselesaikan dari superkelas dan antarmuka AIC dan dapat membayangi nama yang muncul di lingkungan yang melingkupi secara leksikal. Untuk lambda, semua nama diselesaikan secara leksikal.
sumber
A$1.class
tetapi Lambda tidak. Bisakah saya menambahkan ini di Difference?LambdaClass$$Lambda$1/1078694789
. Namun, kelas ini dibuat dengan cepat oleh metafactory lambda, bukan olehjavac
, jadi tidak ada.class
file yang sesuai . Namun, sekali lagi, ini adalah masalah implementasi.Lambdas meskipun fitur hebat, hanya akan bekerja dengan jenis SAM. Artinya, antarmuka hanya dengan satu metode abstrak. Ini akan gagal segera setelah antarmuka Anda berisi lebih dari 1 metode abstrak. Di situlah kelas anonim akan berguna.
Jadi, tidak, kita tidak bisa begitu saja mengabaikan kelas anonim. Untuk diketahui,
sort()
metode Anda bisa lebih disederhanakan, dengan melewatkan deklarasi type forp1
danp2
:Anda juga dapat menggunakan referensi metode di sini. Entah Anda menambahkan
compareByFirstName()
metode diPerson
kelas, dan menggunakan:atau, tambahkan getter for
firstName
, langsung dapatkan metodeComparator
fromComparator.comparing()
:sumber
new @MyTypeAnnotation SomeInterface(){};
. Ini tidak mungkin untuk ekspresi lambda. Untuk detailnya, lihat pertanyaan saya di sini: Menganotasi antarmuka fungsional dari Ekspresi Lambda .Performa Lambda dengan kelas Anonymous
Saat aplikasi diluncurkan, setiap file kelas harus dimuat dan diverifikasi.
Kelas anonim diproses oleh kompilator sebagai subtipe baru untuk kelas atau antarmuka yang diberikan, sehingga akan dihasilkan file kelas baru untuk masing-masing kelas.
Lambda berbeda pada pembuatan bytecode, mereka lebih efisien, menggunakan instruksi dinamis yang dipanggil yang disertakan dengan JDK7.
Untuk Lambdas, instruksi ini digunakan untuk menunda menerjemahkan ekspresi lambda dalam bytecode hingga runtime. (instruksi akan dipanggil untuk pertama kali saja)
Akibatnya ekspresi Lambda akan menjadi metode statis (dibuat saat runtime). (Ada perbedaan kecil dengan kasus stateles dan statefull, mereka diselesaikan melalui argumen metode yang dihasilkan)
sumber
invokedynamic
yang umumnya lebih lambat daripada yanginvokespecial
digunakan untuk membuat instance baru dari kelas anonim. Jadi, dalam hal ini lambda juga lebih lambat (namun, JVM dapat mengoptimalkaninvokedynamic
panggilan hampir sepanjang waktu).invokedynamic
dengan pembuatan kelas ad-hoc sangat cepat dibandingkan dengan kelas anonim yang dikompilasi.Ada perbedaan sebagai berikut:
1) Sintaks
Ekspresi Lambda terlihat rapi dibandingkan dengan Anonymous Inner Class (AIC)
2) Ruang Lingkup
Kelas dalam anonim adalah kelas, yang berarti memiliki ruang lingkup untuk variabel yang ditentukan di dalam kelas dalam.
Padahal, ekspresi lambda bukanlah cakupannya sendiri, tetapi merupakan bagian dari cakupan yang melingkupi.
Aturan serupa berlaku untuk super dan kata kunci ini saat menggunakan di dalam kelas dalam anonim dan ekspresi lambda. Dalam kasus kelas dalam anonim, kata kunci ini mengacu pada cakupan lokal dan kata kunci super mengacu pada kelas super kelas anonim. Sementara dalam kasus ekspresi lambda kata kunci ini merujuk ke objek dari tipe penutup dan super akan merujuk ke kelas super kelas yang melingkupinya.
3) Kinerja
Pada waktu proses, kelas dalam anonim memerlukan pemuatan kelas, alokasi memori, dan inisialisasi objek, serta pemanggilan metode non-statis, sedangkan ekspresi lambda adalah aktivitas waktu kompilasi murni dan tidak menimbulkan biaya tambahan selama waktu proses. Jadi kinerja ekspresi lambda lebih baik dibandingkan dengan kelas dalam anonim. **
** Saya menyadari bahwa poin ini tidak sepenuhnya benar. Silakan lihat pertanyaan berikut untuk detailnya. Kinerja kelas dalam Lambda vs anonim: mengurangi beban pada ClassLoader?
sumber
Lambda di java 8 diperkenalkan untuk pemrograman fungsional. Di mana Anda dapat menghindari kode boilerplate. Saya menemukan artikel menarik ini di lambda's.
http://radar.oreilly.com/2014/04/whats-new-in-java-8-lambdas.html
Sebaiknya gunakan fungsi lambda untuk logika sederhana. Jika menerapkan logika kompleks menggunakan lambda akan menjadi overhead dalam men-debug kode jika terjadi masalah.
sumber
Kelas anonim tetap ada karena lambda bagus untuk fungsi dengan metode abstrak tunggal tetapi untuk semua kasus lain kelas dalam anonim adalah penyelamat Anda.
sumber
invoke dynamic
, lambda tidak diubah kembali ke kelas anonim selama waktu kompilasi (Java tidak harus melalui pembuatan objek, cukup perhatikan tanda tangan metode, dapat mengikat ke metode tanpa membuat objeksumber