Di masa lalu, saya telah mengatakan untuk menyalin koleksi dengan aman, lakukan sesuatu seperti:
public static void doThing(List<String> strs) {
List<String> newStrs = new ArrayList<>(strs);
atau
public static void doThing(NavigableSet<String> strs) {
NavigableSet<String> newStrs = new TreeSet<>(strs);
Tetapi apakah konstruktor "salin" ini, metode dan aliran penciptaan statis yang serupa, benar - benar aman dan di mana aturan ditentukan? Maksud saya adalah jaminan integritas semantik dasar yang ditawarkan oleh bahasa Jawa dan koleksi yang diberlakukan terhadap penelepon jahat, dengan asumsi didukung oleh alasan yang masuk akal SecurityManagerdan tidak ada kekurangan.
Saya senang dengan metode lempar ConcurrentModificationException, NullPointerException, IllegalArgumentException, ClassCastException, dll, atau mungkin bahkan menggantung.
Saya telah memilih Stringsebagai contoh dari argumen tipe yang tidak dapat diubah. Untuk pertanyaan ini, saya tidak tertarik pada salinan yang dalam untuk koleksi jenis yang bisa berubah yang memiliki gotcha sendiri.
(Untuk lebih jelasnya, saya telah melihat kode sumber OpenJDK dan memiliki beberapa jenis jawaban untuk ArrayListdan TreeSet.)
NavigableSetdan Comparablekoleksi berbasis lainnya kadang-kadang dapat mendeteksi jika kelas tidak menerapkan compareTo()dengan benar dan melemparkan pengecualian. Agak tidak jelas apa yang Anda maksud dengan argumen yang tidak dipercaya. Maksud Anda seorang penjahat membuat koleksi String buruk dan ketika Anda menyalinnya ke koleksi Anda, sesuatu yang buruk terjadi? Tidak, kerangka koleksi cukup solid, sudah ada sejak 1.2.
HashSet(dan semua koleksi hashing lainnya secara umum) bergantung pada kebenaran / integritas hashCodeimplementasi elemen, TreeSetdan PriorityQueuebergantung pada Comparator(dan Anda bahkan tidak bisa buat salinan yang setara tanpa menerima komparator khusus jika ada), EnumSetpercaya integritas enumtipe tertentu yang tidak pernah diverifikasi setelah kompilasi, sehingga file kelas, tidak dihasilkan dengan javacatau buatan tangan, dapat menumbangkannya.
new TreeSet<>(strs)mana strsa NavigableSet. Ini bukan salinan massal, karena hasilnya TreeSetakan menggunakan komparator sumber, yang bahkan diperlukan untuk mempertahankan semantik. Jika Anda baik-baik saja dengan hanya memproses elemen yang terkandung, toArray()adalah cara untuk pergi; bahkan akan menjaga urutan iterasi. Ketika Anda baik-baik saja dengan "mengambil elemen, memvalidasi elemen, menggunakan elemen", Anda bahkan tidak perlu membuat salinan. Masalah dimulai ketika Anda ingin memverifikasi semua elemen, diikuti dengan menggunakan semua elemen. Kemudian, Anda tidak dapat mempercayai TreeSetpembanding khusus salinan
checkcastuntuk setiap elemen, adalah toArraydengan tipe tertentu. Kami selalu mengakhirinya. Koleksi generik bahkan tidak tahu jenis elemen mereka yang sebenarnya, jadi pembuat salinan mereka tidak dapat memberikan fungsionalitas yang serupa. Tentu saja, Anda dapat menunda pemeriksaan apa pun untuk penggunaan yang benar sebelumnya, tetapi kemudian, saya tidak tahu apa tujuan pertanyaan Anda. Anda tidak perlu "integritas semantik", ketika Anda baik-baik saja dengan memeriksa dan gagal segera sebelum menggunakan elemen.