JDK 7: Pengendali Berlian

Project Coin menyediakan banyak "penambahbaikan bahasa kecil" sebagai sebahagian daripada ciri JDK 7 yang baru. Saya baru-baru ini menulis blog mengenai Project Coin menghidupkan Strings dan dalam catatan ini saya menulis mengenai Diamond Operator baru ( ).

Pengendali Berlian mengurangkan beberapa verbositas Java di sekitar generik dengan meminta penyusun menyimpulkan jenis parameter untuk pembina kelas generik. Cadangan asal untuk menambahkan Diamond Operator ke bahasa Java dibuat pada bulan Februari 2009 dan merangkumi contoh mudah ini:

Sebagai contoh, pertimbangkan penyataan tugasan berikut:

Peta anagrams = HashMap baru ();

Ini agak panjang, sehingga dapat diganti dengan ini:

Peta anagrams = HashMap baru ();

Contoh di atas yang diberikan dalam cadangan Jeremy Manson (yang merupakan salah satu yang pertama sebagai tindak balas kepada panggilan untuk idea Project Coin) adalah mudah, tetapi menunjukkan dengan tepat bagaimana Diamond Operator diterapkan dalam JDK 7. Cadangan Manson juga memberikan kesan penting mengapa penambahan ini adalah wajar:

Keperluan bahawa parameter jenis digandakan tidak perlu seperti

ini mendorong orang yang tidak bernasib baik

kelebihan kaedah kilang statik, hanya kerana inferens jenis

berfungsi pada kaedah panggilan.

Dengan kata lain, penambahan Coin Projek JDK 7 Diamond Operator membawa inferens jenis kepada pembina yang telah tersedia dengan kaedah. Dengan kaedah inferensi jenis secara implisit dilakukan apabila seseorang meninggalkan spesifikasi jenis parameter yang jelas. Sebaliknya, operator berlian mesti ditentukan secara jelas untuk "memberitahu" penyusun untuk menyimpulkan jenisnya.

Dalam cadangan asalnya, Manson menunjukkan bahawa sintaks tanpa operator berlian khas tidak dapat digunakan untuk menyiratkan jenis secara tidak langsung kerana "untuk tujuan keserasian ke belakang, Peta baru () menunjukkan jenis mentah, dan oleh itu tidak dapat digunakan untuk jenis inferens. " Halaman Jenis Inferensi Pelajaran Generik Pembelajaran jejak Bahasa Jawa Tutorial Java merangkumi bahagian yang disebut "Jenis Inferensi dan Instansiasi Kelas Generik" yang telah diperbarui untuk mencerminkan Java SE 7. Bahagian ini juga menerangkan mengapa pengendali mesti ditentukan untuk memberitahu penyusun secara eksplisit untuk menggunakan inferens jenis pada contoh:

Perhatikan bahawa untuk memanfaatkan inferens jenis automatik semasa instansi kelas generik, anda mesti menentukan operator berlian. Dalam contoh berikut, penyusun menghasilkan amaran penukaran yang tidak diperiksa kerana konstruktor HashMap () merujuk kepada jenis mentah HashMap, bukan Peta menaip

Dalam Item 24 ("Menghilangkan Peringatan yang Tidak Diperiksa") Edisi Kedua Java Berkesan, Josh Bloch menekankan dalam teks tebal , "Hapuskan setiap peringatan yang tidak dapat Anda periksa." Bloch menunjukkan contoh amaran penukaran yang tidak dicentang yang berlaku apabila seseorang menyusun kod yang menggunakan jenis mentah di sebelah kanan deklarasi. Penyenaraian kod seterusnya menunjukkan kod yang akan membawa kepada amaran ini.

final Map
     
       statesToCities = new HashMap(); // raw! 
     

Dua tangkapan skrin seterusnya menunjukkan tindak balas penyusun terhadap baris kod di atas. Gambar pertama menunjukkan mesej apabila tidak ada amaran -Xlint yang diaktifkan dan yang kedua menunjukkan amaran yang lebih eksplisit yang berlaku apabila -Xlint:uncheckeddiberikan sebagai argumen kepada javac.

Sekiranya Java Berkesan , Bloch menunjukkan bahawa amaran yang tidak diperiksa ini mudah ditangani dengan memberikan secara jelas jenis parameter kepada contoh kelas generik. Dengan JDK 7, ini akan menjadi lebih mudah! Daripada perlu menambahkan teks eksplisit dengan nama jenis ini, jenisnya dapat disimpulkan dalam banyak kes dan spesifikasi operator berlian memberitahu penyusun untuk membuat kesimpulan ini daripada menggunakan jenis mentah.

Penyenaraian kod Java seterusnya memberikan contoh konsep yang ringkas. Ada metode yang menunjukkan instansiasi Set mentah, instansiasi Set dengan spesifikasi eksplisit dari jenis parameternya, dan instansiasi Set dengan jenis parameter yang disimpulkan kerana spesifikasi operator berlian ( ).

package dustin.examples; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import static java.lang.System.out; /** * Very simple demonstration of JDK 7's/Project Coin's "Diamond Operator." */ public class DiamondOperatorDemo { /** Use of "raw" type. */ private static Set rawWithoutExplicitTyping() { final Set names = new HashSet(); addNames(names); return names; } /** Explicitly specifying generic class's instantiation parameter type. */ private static Set explicitTypingExplicitlySpecified() { final Set names = new HashSet(); addNames(names); return names; } /** * Inferring generic class's instantiation parameter type with JDK 7's * 'Diamond Operator.' */ private static Set explicitTypingInferredWithDiamond() { final Set names = new HashSet(); addNames(names); return names; } private static void addNames(final Set namesToAddTo) { namesToAddTo.add("Dustin"); namesToAddTo.add("Rett"); namesToAddTo.add("Homer"); } /** * Main executable function. */ public static void main(final String[] arguments) { out.println(rawWithoutExplicitTyping()); out.println(explicitTypingExplicitlySpecified()); out.println(explicitTypingInferredWithDiamond()); } } 

Apabila kod di atas disusun, hanya kotak "mentah" yang membawa kepada amaran.

Pada ketika ini, kita boleh melihat apa yang diberitahu oleh javap mengenai tiga kaedah ini. Ini dilakukan dalam kes ini dengan perintah ( -vpilihan untuk verbose memberikan semua perincian berair dan -pmemaparkan perincian berair ini untuk privatekaedahnya):

javap -v -p -classpath classes dustin.examples.DiamondOperatorDemo 

Kerana kaedah ini semuanya ada dalam satu kelas, terdapat satu aliran output untuk keseluruhan kelas. Namun, untuk mempermudah membandingkannya, saya telah memotong dan menempelkan output ke dalam format yang menyelaraskan output javap untuk setiap kaedah antara satu sama lain. Setiap lajur menunjukkan javapoutput untuk salah satu kaedah. Saya telah menukar warna fon kaedah tertentu menjadi biru untuk menjadikannya menonjol dan melabelkan output lajur itu.

Selain nama kaedah itu sendiri, TIDAK ADA perbezaan dalam javapoutput. Ini kerana penghapusan jenis generik Java bermaksud pembezaan berdasarkan jenis tidak tersedia pada waktu runtime. Tutorial Java pada Generik merangkumi halaman yang disebut Type Erasure yang menerangkan ini:

Penyusun membuang semua maklumat mengenai argumen jenis sebenar pada masa penyusunan.

Penghapusan jenis wujud supaya kod baru dapat terus bersambung dengan kod lama. Menggunakan jenis mentah untuk alasan lain dianggap sebagai amalan pengaturcaraan yang buruk dan harus dielakkan seboleh mungkin.

Seperti petikan di atas mengingatkan kita, penghapusan bermaksud bahawa untuk mengekodkan jenis mentah tidak berbeza dengan jenis parameter yang ditaip secara eksplisit, tetapi juga mendorong pembangun untuk tidak menggunakan jenis mentah kecuali untuk mengintegrasikan dengan kod warisan.

Kesimpulannya

Kemasukan operator berlian ( ) di Java SE 7 bermaksud bahawa kod yang menunjukkan kelas generik boleh kurang verbose. Bahasa pengekodan secara umum, dan Java khususnya, bergerak menuju gagasan seperti konvensi mengenai konfigurasi, konfigurasi dengan pengecualian, dan menyimpulkan perkara sesering mungkin daripada memerlukan spesifikasi eksplisit. Bahasa yang ditaip secara dinamik terkenal dengan inferens jenis, tetapi bahkan Java yang ditaip secara statik dapat melakukan lebih banyak daripada yang dilakukannya dan operator berlian adalah contohnya.

Pengeposan asal boleh didapati di //marxsoftware.blogspot.com/

Kisah ini, "JDK 7: The Diamond Operator" pada asalnya diterbitkan oleh JavaWorld.