Mengapa Java 8 tidak menyertakan koleksi tidak berubah?

130

Tim Java telah melakukan banyak pekerjaan untuk menghilangkan hambatan pemrograman fungsional di Jawa 8. Secara khusus, perubahan pada java.util Collections melakukan pekerjaan yang bagus untuk mengubah transformasi menjadi operasi yang mengalir sangat cepat. Mengingat betapa baiknya pekerjaan yang telah mereka lakukan dengan menambahkan fungsi kelas satu dan metode fungsional pada koleksi, mengapa mereka benar-benar gagal untuk menyediakan koleksi yang tidak dapat diubah atau bahkan antarmuka koleksi yang tidak dapat diubah?

Tanpa mengubah kode apa pun yang ada, tim Java dapat kapan saja menambahkan antarmuka tidak berubah yang sama dengan yang bisa diubah, minus metode "set" dan membuat antarmuka yang ada diperluas darinya, seperti ini:

                  ImmutableIterable
     ____________/       |
    /                    |
Iterable        ImmutableCollection
   |    _______/    /          \   \___________
   |   /           /            \              \
 Collection  ImmutableList  ImmutableSet  ImmutableMap  ...
    \  \  \_________|______________|__________   |
     \  \___________|____________  |          \  |
      \___________  |            \ |           \ |
                  List            Set           Map ...

Tentu, operasi seperti List.add () dan Map.put () saat ini mengembalikan nilai boolean atau sebelumnya untuk kunci yang diberikan untuk menunjukkan apakah operasi berhasil atau gagal. Koleksi yang tidak dapat diubah harus memperlakukan metode seperti pabrik dan mengembalikan koleksi baru yang mengandung elemen yang ditambahkan - yang tidak sesuai dengan tanda tangan saat ini. Tapi itu bisa diatasi dengan menggunakan nama metode yang berbeda seperti ImmutableList.append () atau .addAt () dan ImmutableMap.putEntry (). Verbositas yang dihasilkan akan lebih besar daripada manfaat dari bekerja dengan koleksi yang tidak dapat diubah, dan sistem tipe akan mencegah kesalahan memanggil metode yang salah. Seiring waktu, metode lama bisa ditinggalkan.

Menangkan koleksi abadi:

  • Kesederhanaan - alasan tentang kode lebih sederhana ketika data yang mendasarinya tidak berubah.
  • Dokumentasi - jika suatu metode mengambil antarmuka koleksi yang tidak dapat diubah, Anda tahu itu tidak akan mengubah koleksi itu. Jika suatu metode mengembalikan koleksi yang tidak dapat diubah, Anda tahu Anda tidak bisa memodifikasinya.
  • Concurrency - koleksi yang tidak dapat diubah dapat dibagikan secara aman di seluruh utas.

Sebagai seseorang yang telah mencicipi bahasa yang menganggap tidak dapat diubah, sangat sulit untuk kembali ke Wild West dari mutasi yang merajalela. Koleksi Clojure (urutan abstraksi) sudah memiliki semua yang disediakan oleh koleksi Java 8, plus ketidakmampuan (meskipun mungkin menggunakan memori dan waktu ekstra karena daftar tautan yang disinkronkan alih-alih streaming). Scala memiliki koleksi yang bisa berubah dan tidak dapat diubah dengan satu set operasi penuh, dan meskipun operasi-operasi itu bersemangat, memanggil .iterator memberikan pandangan malas (dan ada cara lain untuk mengevaluasi mereka dengan malas). Saya tidak melihat bagaimana Java dapat terus bersaing tanpa koleksi abadi.

Adakah yang bisa mengarahkan saya ke sejarah atau diskusi tentang ini? Tentunya itu adalah tempat umum.

GlenPeterson
sumber
9
Terkait dengan ini - Ayende baru-baru ini membuat blog tentang koleksi dan koleksi abadi di C #, dengan tolok ukur. ayende.com/blog/tags/performance - tl; dr - immutability lambat .
Oded
20
dengan hierarki Anda, saya dapat memberi Anda ImmutableList dan kemudian mengubahnya pada Anda ketika Anda tidak mengharapkannya yang dapat merusak banyak hal, seperti halnya Anda hanya memiliki constkoleksi
ratchet freak
18
@Oded Immutability lambat, tetapi begitu juga penguncian. Begitu juga menjaga sejarah. Kesederhanaan / kebenaran bernilai kecepatan dalam banyak situasi. Dengan koleksi kecil, kecepatan bukanlah masalah. Analisis Ayende didasarkan pada asumsi bahwa Anda tidak memerlukan riwayat, penguncian, atau kesederhanaan dan bahwa Anda bekerja dengan kumpulan data besar. Terkadang itu benar, tetapi itu bukan hal yang selalu baik. Ada trade-off.
GlenPeterson
5
@ GlenPeterson itulah salinan defensif dan Collections.unmodifiable*()untuk apa. tapi jangan memperlakukan ini sebagai tidak berubah ketika tidak
ratchet freak
13
Eh? Jika fungsi Anda mengambil ImmutableListdalam diagram itu, orang bisa lewat dalam bisa berubah List? Tidak, itu pelanggaran LSP yang sangat buruk.
Telastyn

Jawaban:

113

Karena koleksi abadi benar-benar membutuhkan berbagi agar dapat digunakan. Kalau tidak, setiap operasi menjatuhkan seluruh daftar ke tumpukan. Bahasa yang sepenuhnya tidak berubah, seperti Haskell, menghasilkan jumlah sampah yang mencengangkan tanpa optimalisasi dan pembagian yang agresif. Memiliki koleksi yang hanya dapat digunakan dengan <50 elemen tidak layak dimasukkan ke perpustakaan standar.

Lebih jauh lagi, koleksi yang tidak dapat diubah seringkali memiliki implementasi yang berbeda secara fundamental dibandingkan dengan koleksi yang dapat berubah. Pertimbangkan misalnya ArrayList, kekekalan yang efisien tidak ArrayListakan menjadi array sama sekali! Ini harus diimplementasikan dengan pohon seimbang dengan faktor percabangan besar, Clojure menggunakan 32 IIRC. Membuat koleksi yang dapat diubah menjadi "tidak berubah" dengan hanya menambahkan pembaruan fungsional adalah bug kinerja seperti halnya kebocoran memori.

Selain itu, berbagi tidak dapat dilakukan di Jawa. Java menyediakan terlalu banyak pengait yang tidak dibatasi untuk berubah-ubah dan merujuk kesetaraan untuk menjadikan berbagi "hanya pengoptimalan". Mungkin akan sedikit mengganggu Anda jika Anda bisa memodifikasi elemen dalam daftar, dan menyadari Anda baru saja memodifikasi elemen di 20 versi lain dari daftar yang Anda miliki.

Ini juga mengesampingkan kelas besar optimasi yang sangat vital untuk kekekalan yang efisien, berbagi, aliran fusi, apa saja, mutabilitas menghancurkannya. (Itu akan membuat slogan yang bagus untuk penginjil FP)

jozefg
sumber
21
Contoh saya berbicara tentang antarmuka yang tidak dapat diubah . Java bisa memberikan rangkaian lengkap dari kedua bisa berubah dan abadi implementasi dari orang-orang interface yang akan membuat diperlukan trade-off. Terserah programmer untuk memilih bisa berubah atau tidak berubah yang sesuai. Pemrogram harus tahu kapan harus menggunakan Daftar vs. Setel sekarang. Anda biasanya tidak memerlukan versi yang bisa diubah hingga Anda memiliki masalah kinerja, dan itu mungkin hanya diperlukan sebagai pembangun. Bagaimanapun, memiliki antarmuka yang tidak dapat diubah akan menjadi kemenangan tersendiri.
GlenPeterson
4
Saya membaca jawaban Anda lagi dan saya pikir Anda mengatakan bahwa Jawa memiliki asumsi mendasar tentang ketidakstabilan (mis. Biji jawa) dan bahwa koleksi hanyalah puncak gunung es dan ukiran ujung itu tidak akan menyelesaikan masalah yang mendasarinya. Poin yang valid. Saya mungkin menerima jawaban ini dan mempercepat adopsi saya atas Scala! :-)
GlenPeterson
8
Saya tidak yakin koleksi yang tidak dapat diubah membutuhkan kemampuan untuk berbagi bagian yang umum agar bermanfaat. Jenis abadi yang paling umum di Jawa, koleksi karakter abadi, digunakan untuk memungkinkan berbagi tetapi tidak lagi. Hal utama yang membuatnya berguna adalah kemampuan untuk dengan cepat menyalin data dari Stringdalam StringBuffer, memanipulasi, dan kemudian menyalin data ke dalam kekekalan baru String. Menggunakan pola seperti itu dengan set dan daftar mungkin sama baiknya dengan menggunakan tipe yang tidak dapat diubah yang dirancang untuk memfasilitasi produksi instance yang sedikit berubah, tetapi masih bisa lebih baik ...
supercat
3
Sangat mungkin untuk membuat koleksi abadi di Jawa menggunakan berbagi. Item yang disimpan dalam koleksi adalah referensi dan referensi mereka dapat dimutasi - jadi apa? Perilaku seperti itu sudah merusak koleksi yang ada seperti HashMap dan TreeSet, namun itu diimplementasikan di Jawa. Dan jika beberapa koleksi berisi referensi ke objek yang sama, sepenuhnya diharapkan bahwa memodifikasi objek akan menyebabkan perubahan yang terlihat ketika dilihat dari semua koleksi.
Solomonoff's Secret
4
jozefg, sangat mungkin untuk menerapkan koleksi abadi yang efisien di JVM dengan pembagian struktural. Scala dan Clojure memilikinya sebagai bagian dari perpustakaan standar mereka, kedua implementasi didasarkan pada HAMT Phil Bagwell (Hash Array Mapped Trie). Pernyataan Anda tentang Clojure yang menerapkan struktur data yang tidak dapat diubah dengan pohon-pohon BALANCED sepenuhnya salah.
sesm
78

Koleksi yang tidak dapat diubah bukan subtipe dari koleksi yang tidak dapat diubah. Sebaliknya, koleksi yang bisa berubah dan tidak berubah adalah saudara kandung dari koleksi yang dapat dibaca. Sayangnya, konsep "readable", "read-only", dan "immutable" nampaknya menjadi kabur bersama, meskipun mereka memiliki tiga arti berbeda.

  • Kelas basis koleksi atau jenis antarmuka yang dapat dibaca menjanjikan bahwa orang dapat membaca item, dan tidak menyediakan sarana langsung untuk mengubah koleksi, tetapi tidak menjamin bahwa kode yang menerima referensi tidak dapat membuang atau memanipulasinya sedemikian rupa sehingga memungkinkan modifikasi.

  • Antarmuka koleksi read-only tidak termasuk anggota baru, tetapi hanya boleh dilaksanakan oleh kelas yang menjanjikan bahwa tidak ada cara untuk memanipulasi referensi untuk itu sedemikian rupa untuk mengubah koleksi atau menerima referensi untuk sesuatu itu bisa dilakukan. Namun, itu tidak menjanjikan bahwa koleksi tidak akan dimodifikasi oleh sesuatu yang lain yang memiliki referensi ke internal. Perhatikan bahwa antarmuka kumpulan read-only mungkin tidak dapat mencegah implementasi dengan kelas yang bisa diubah, tetapi dapat menentukan bahwa setiap implementasi, atau kelas yang berasal dari suatu implementasi, yang memungkinkan mutasi akan dianggap sebagai implementasi "tidak sah" atau turunan dari suatu implementasi .

  • Koleksi yang tidak berubah adalah koleksi yang akan selalu memiliki data yang sama selama referensi apa pun ada. Setiap implementasi antarmuka yang tidak dapat diubah yang tidak selalu mengembalikan data yang sama dalam menanggapi permintaan tertentu rusak.

Hal ini kadang-kadang berguna untuk memiliki sangat terkait jenis bisa berubah dan abadi koleksi yang baik melaksanakan atau berasal dari jenis yang sama "dibaca", dan memiliki tipe dibaca meliputi AsImmutable, AsMutable, dan AsNewMutablemetode. Desain semacam itu memungkinkan kode yang ingin menyimpan data dalam koleksi untuk dipanggil AsImmutable; metode itu akan membuat salinan defensif jika koleksi dapat diubah, tetapi lewati salinan jika sudah tidak berubah.

supercat
sumber
1
Jawaban yang bagus Koleksi yang tidak berubah dapat memberi Anda jaminan yang cukup kuat terkait keamanan benang dan bagaimana Anda dapat beralasan tentangnya seiring berjalannya waktu. Koleksi Readable / Read-only tidak. Bahkan, untuk menghormati prinsip substitusi liskov, Read-Only dan Immutable mungkin harus tipe dasar abstrak dengan metode final dan anggota pribadi untuk memastikan bahwa tidak ada kelas turunan yang dapat menghancurkan jaminan yang diberikan oleh tipe tersebut. Atau mereka harus tipe yang sepenuhnya konkret yang membungkus koleksi (Read-Only), atau selalu mengambil salinan defensif (Tidak Berubah). Ini adalah bagaimana jambu ImmutableList melakukannya.
Laurent Bourgault-Roy
1
@ LaurentBourgault-Roy: Ada beberapa keuntungan untuk tipe yang tidak dapat disegel dan diwariskan. Jika seseorang tidak ingin mengizinkan kelas turunan tidak sah untuk memecahkan invarian seseorang, tipe yang tersegel dapat menawarkan perlindungan terhadap hal itu sementara kelas inheren tidak menawarkannya. Di sisi lain, dimungkinkan untuk kode yang mengetahui sesuatu tentang data yang dimilikinya untuk menyimpannya jauh lebih kompak daripada jenis yang tidak tahu apa-apa tentang itu. Pertimbangkan, misalnya, tipe ReadableIndexedIntSequence yang merangkum urutan int, dengan metode getLength()dan getItemAt(int).
supercat
1
@ LaurentBourgault-Roy: Diberikan ReadableIndexedIntSequence, seseorang dapat menghasilkan sebuah instance dari tipe yang tidak dapat diubah dengan array dengan menyalin semua item ke dalam sebuah array, tetapi anggaplah bahwa implementasi tertentu hanya mengembalikan panjang 16777216 ((long)index*index)>>24untuk setiap item. Itu akan menjadi urutan bilangan bulat yang sah dan sah, tetapi menyalinnya ke sebuah array akan menghabiskan banyak waktu dan memori.
supercat
1
Saya sangat setuju. Solusi saya memberi Anda kebenaran (sampai titik tertentu), tetapi untuk mendapatkan kinerja dengan dataset besar, Anda harus memiliki struktur dan desain yang gigih untuk kekekalan dari awal. Untuk koleksi kecil, Anda dapat mengambil salinan abadi dari waktu ke waktu. Saya ingat bahwa Scala melakukan beberapa analisis dari berbagai program dan menemukan bahwa sekitar 90% dari daftar yang diinvestasikan adalah 10 atau kurang item.
Laurent Bourgault-Roy
1
@ LaurentBourgault-Roy: Pertanyaan mendasar adalah apakah seseorang mempercayai orang untuk tidak menghasilkan implementasi yang rusak atau kelas turunan. Jika ada, dan jika antarmuka / kelas dasar menyediakan metode asMutable / asImmutable, dimungkinkan untuk meningkatkan kinerja dengan banyak urutan besarnya [misalnya membandingkan biaya panggilan asImmutablepada instance dari urutan yang ditentukan di atas versus biaya membangun salinan yang didukung oleh array yang tidak dapat diubah]. Saya berpendapat bahwa memiliki antarmuka yang ditentukan untuk tujuan seperti itu mungkin lebih baik daripada mencoba menggunakan pendekatan ad-hoc; IMHO, alasan terbesar ...
supercat
15

Java Collections Framework menyediakan kemampuan untuk membuat versi read-only dari koleksi dengan menggunakan enam metode statis di kelas java.util.Collections :

Seperti yang seseorang tunjukkan dalam komentar pada pertanyaan awal, koleksi yang dikembalikan mungkin tidak dianggap tidak dapat diubah karena meskipun koleksi tidak dapat dimodifikasi (tidak ada anggota yang dapat ditambahkan atau dihapus dari koleksi semacam itu), objek yang sebenarnya dirujuk oleh koleksi dapat dimodifikasi jika jenis objeknya memungkinkan.

Namun, masalah ini akan tetap terlepas dari apakah kode mengembalikan satu objek, atau kumpulan objek yang tidak dapat dimodifikasi. Jika tipe memungkinkan objeknya dimutasi, maka keputusan itu dibuat dalam desain tipe dan saya tidak melihat bagaimana perubahan pada JCF dapat mengubah itu. Jika ketetapan penting, maka anggota koleksi harus dari tipe yang tidak dapat diubah.

Arkanon
sumber
4
Desain koleksi yang tidak dapat dimodifikasi akan sangat ditingkatkan jika pembungkus menyertakan indikasi apakah benda yang dibungkus sudah tidak berubah, dan ada immutableListdll. Metode pabrik yang akan mengembalikan pembungkus baca-saja di sekitar salinan izin masuk daftar kecuali daftar yang lewat sudah tidak dapat diubah . Akan mudah untuk membuat tipe yang ditentukan pengguna seperti itu tetapi untuk satu masalah: tidak akan ada cara bagi joesCollections.immutableListmetode untuk mengenali bahwa itu tidak perlu menyalin objek yang dikembalikan oleh fredsCollections.immutableList.
supercat
8

Ini pertanyaan yang sangat bagus. Saya senang menghibur ide bahwa dari semua kode yang ditulis dalam java dan berjalan di jutaan komputer di seluruh dunia, setiap hari, sepanjang waktu, sekitar setengah dari total siklus jam harus dihabiskan dengan melakukan apa pun selain membuat salinan keamanan koleksi yang dikembalikan oleh fungsi. (Dan pengumpulan sampah ini milidetik setelah pembuatannya.)

Persentase programmer java menyadari keberadaan unmodifiableCollection()keluarga metode Collectionskelas, tetapi bahkan di antara mereka, banyak yang tidak peduli dengan itu.

Dan saya tidak bisa menyalahkan mereka: sebuah antarmuka yang berpura-pura baca-tulis tetapi akan melempar UnsupportedOperationExceptionjika Anda membuat kesalahan dengan menggunakan salah satu metode 'tulis' itu adalah hal yang sangat jahat untuk dimiliki!

Sekarang, antarmuka seperti Collectionyang akan hilang add(), remove()dan clear()metode tidak akan menjadi antarmuka "ImmutableCollection"; itu akan menjadi antarmuka "UnmodifiableCollection". Faktanya, tidak pernah ada antarmuka "ImmutableCollection", karena ketidakmampuan adalah sifat implementasi, bukan karakteristik antarmuka. Saya tahu, itu tidak terlalu jelas; coba saya jelaskan.

Misalkan seseorang memberi Anda antarmuka koleksi hanya-baca; apakah aman untuk meneruskannya ke utas lain? Jika Anda tahu pasti bahwa itu merupakan koleksi yang benar-benar abadi, maka jawabannya adalah "ya"; Sayangnya, karena ini adalah antarmuka, Anda tidak tahu bagaimana penerapannya, jadi jawabannya haruslah tidak : untuk semua yang Anda tahu, itu mungkin tampilan yang tidak dapat diubah (untuk Anda) dari koleksi yang sebenarnya bisa diubah, (seperti apa yang Anda dapatkan Collections.unmodifiableCollection(),) jadi mencoba membaca darinya sementara utas lain memodifikasinya akan menghasilkan pembacaan data yang korup.

Jadi, apa yang telah Anda jelaskan pada dasarnya adalah sekumpulan antarmuka pengumpulan yang tidak "Tidak Berubah", tetapi "Tidak Dapat Diubah". Penting untuk dipahami bahwa "Tidak Dapat Diubah" hanya berarti bahwa siapa pun yang memiliki referensi ke antarmuka seperti itu dicegah dari memodifikasi koleksi yang mendasarinya, dan mereka dicegah hanya karena antarmuka tidak memiliki metode modifikasi apa pun, bukan karena koleksi yang mendasarinya tidak dapat diubah. Koleksi yang mendasarinya mungkin bisa berubah; Anda tidak memiliki pengetahuan tentang, dan tidak memiliki kendali atas itu.

Untuk memiliki koleksi yang tidak berubah, mereka harus berupa kelas , bukan antarmuka!

Kelas-kelas koleksi yang tidak berubah ini harus final, sehingga ketika Anda diberikan referensi ke koleksi tersebut, Anda tahu pasti bahwa itu akan berperilaku sebagai koleksi yang tidak berubah, apa pun yang Anda, atau siapa pun yang memiliki referensi untuk itu, mungkin lakukan dengan itu.

Jadi, dalam rangka untuk memiliki lengkap set koleksi di java, (atau bahasa imperatif deklaratif lainnya,) kita akan memerlukan berikut ini:

  1. Satu set antarmuka koleksi yang tidak dapat dimodifikasi .

  2. Seperangkat antarmuka koleksi yang bisa berubah , memperluas yang tidak dapat dimodifikasi.

  3. Seperangkat kelas koleksi yang dapat diubah yang mengimplementasikan antarmuka yang dapat diubah, dan dengan ekstensi juga antarmuka yang tidak dapat dimodifikasi.

  4. Seperangkat kelas koleksi yang tidak dapat diubah , mengimplementasikan antarmuka yang tidak dapat dimodifikasi, tetapi sebagian besar diedarkan sebagai kelas, untuk menjamin keabadian.

Saya telah menerapkan semua hal di atas untuk bersenang-senang, dan saya menggunakannya dalam proyek, dan mereka bekerja seperti pesona.

Alasan mengapa mereka bukan bagian dari runtime java mungkin karena dianggap bahwa ini akan terlalu banyak / terlalu rumit / terlalu sulit untuk dipahami.

Secara pribadi, saya pikir apa yang saya jelaskan di atas tidak cukup; Satu hal lagi yang tampaknya diperlukan adalah seperangkat antarmuka & kelas yang bisa berubah-ubah untuk kekekalan struktural . (Yang mungkin disebut "Kaku" karena awalan "StructurallyImmutable" terlalu panjang.)

Mike Nakis
sumber
Poin bagus. Dua perincian: 1. Koleksi yang tidak dapat diubah membutuhkan tanda tangan metode tertentu, khususnya (menggunakan Daftar sebagai contoh): List<T> add(T t)- semua metode "mutator" harus mengembalikan koleksi baru yang mencerminkan perubahan. 2. Baik atau buruk, Antarmuka sering mewakili kontrak di samping tanda tangan. Serializable adalah salah satu antarmuka tersebut. Demikian pula, Sebanding mensyaratkan Anda menerapkan compareTo()metode Anda dengan benar untuk bekerja dengan benar dan idealnya kompatibel dengan equals()dan hashCode().
GlenPeterson
Oh, saya bahkan tidak memiliki imutabilitas mutasi-by-copy dalam pikiran. Apa yang saya tulis di atas mengacu pada koleksi sederhana yang tidak dapat diubah yang benar - benar tidak memiliki metode seperti add(). Tapi saya kira jika metode mutator ditambahkan ke kelas yang tidak dapat diubah, maka mereka perlu mengembalikan kelas yang juga tidak dapat diubah. Jadi, jika ada masalah mengintai di sana, saya tidak melihatnya.
Mike Nakis
Apakah implementasi Anda tersedia untuk umum? Saya seharusnya bertanya ini bulan lalu. Pokoknya, milikku adalah: github.com/GlenKPeterson/UncleJim
GlenPeterson
4
Suppose someone hands you such a read-only collection interface; is it safe to pass it to another thread?Misalkan seseorang memberi Anda contoh antarmuka koleksi yang bisa diubah. Apakah aman untuk memanggil metode apa pun di dalamnya? Anda tidak tahu bahwa implementasinya tidak berulang selamanya, melempar pengecualian, atau sepenuhnya mengabaikan kontrak antarmuka. Mengapa memiliki standar ganda khusus untuk koleksi tidak berubah?
Doval
1
IMHO alasan Anda terhadap antarmuka yang bisa berubah adalah salah. Anda dapat menulis implementasi yang bisa diubah dari antarmuka yang tidak dapat diubah, dan kemudian rusak. Tentu. Tapi itu salahmu karena kamu melanggar kontrak. Berhentilah melakukan itu. Tidak ada bedanya dengan memecahkan a SortedSetdengan mensubklasifikasikan set dengan implementasi yang tidak sesuai. Atau dengan melewati yang tidak konsisten Comparable. Hampir semuanya bisa rusak jika Anda mau. Saya kira, itulah yang dimaksud @Doval dengan "standar ganda".
maaartinus
2

Koleksi yang tidak dapat diubah dapat menjadi sangat rekursif, dibandingkan satu sama lain, dan tidak efisien tanpa alasan jika kesetaraan objek adalah dengan secureHash. Ini disebut hutan merkle. Itu bisa per koleksi atau di dalam bagian-bagiannya seperti pohon AVL (penyeimbang sendiri) untuk peta yang diurutkan.

Kecuali semua objek java dalam koleksi ini memiliki id unik atau bitstring untuk hash, koleksi tidak memiliki hash untuk secara unik nama itu sendiri.

Contoh: Pada laptop 4x1.6ghz saya, saya dapat menjalankan 200K sha256s per detik dari ukuran terkecil yang cocok dalam 1 siklus hash (hingga 55 byte), dibandingkan dengan op 500k HashMap atau ops 3M dalam hashtable long rs. 200K / log (collectionSize) koleksi baru per detik cukup cepat untuk beberapa hal di mana integritas data dan skalabilitas global anonim penting.

Ben Rayfield
sumber
-3

Performa. Koleksi berdasarkan sifatnya bisa sangat besar. Menyalin 1000 elemen ke struktur baru dengan 1001 elemen alih-alih memasukkan elemen tunggal benar-benar mengerikan.

Konkurensi. Jika Anda memiliki beberapa utas yang berjalan, mereka mungkin ingin mendapatkan versi koleksi saat ini dan bukan versi yang disahkan 12 jam yang lalu ketika utas dimulai.

Penyimpanan. Dengan objek yang tidak dapat diubah di lingkungan multi-utas, Anda dapat berakhir dengan puluhan salinan objek "yang sama" di berbagai titik siklus hidupnya. Tidak masalah untuk Kalender atau objek Tanggal tetapi ketika koleksi 10.000 widget ini akan membunuh Anda.

James Anderson
sumber
12
Koleksi yang tidak dapat diubah hanya membutuhkan penyalinan jika Anda tidak dapat berbagi karena sifatnya yang dapat berubah-ubah seperti yang dimiliki Java. Konkurensi umumnya lebih mudah dengan koleksi yang tidak dapat diubah karena tidak memerlukan penguncian; dan untuk visibilitas Anda selalu dapat memiliki referensi yang bisa berubah ke koleksi yang tidak dapat diubah (umum di OCaml). Dengan berbagi, pembaruan pada dasarnya bisa gratis. Anda mungkin melakukan alokasi logaritmik lebih banyak daripada dengan struktur yang bisa berubah, tetapi pada pembaruan, banyak sub-proyek yang kedaluwarsa dapat segera dibebaskan atau digunakan kembali, sehingga Anda tidak perlu memiliki overhead memori yang lebih tinggi.
Jon Purdy
4
Masalah pasangan. Koleksi di Clojure dan Scala keduanya tidak berubah, tetapi mendukung salinan ringan. Menambahkan elemen 1001 berarti menyalin kurang dari 33 elemen, ditambah membuat beberapa petunjuk baru. Jika Anda berbagi koleksi yang dapat diubah di utas, Anda memiliki semua jenis masalah sinkronisasi saat Anda mengubahnya. Operasi seperti "hapus ()" adalah mimpi buruk. Juga, koleksi yang tidak dapat diubah dapat dibangun secara bergantian, lalu disalin sekali ke versi yang tidak dapat diubah yang aman untuk dibagikan di seluruh utas.
GlenPeterson
4
Menggunakan konkurensi sebagai argumen menentang ketidakberdayaan adalah tidak biasa. Duplikat juga.
Tom Hawtin - tackline
4
Sedikit jengkel tentang suara di sini. OP bertanya mengapa mereka tidak menerapkan koleksi abadi, dan, saya memberikan jawaban yang dipertimbangkan untuk pertanyaan itu. Agaknya satu-satunya jawaban yang bisa diterima di kalangan para pecinta mode adalah "karena mereka membuat kesalahan". Saya benar-benar memiliki beberapa pengalaman dengan ini harus refactor potongan besar kode menggunakan kelas BigDecimal dinyatakan sangat baik murni karena kinerja yang buruk karena kekekalan 512 kali menggunakan double dan beberapa bermain-main untuk memperbaiki desimal.
James Anderson
3
@JamesAnderson: Masalah saya dengan jawaban Anda: "Kinerja" - Anda bisa mengatakan bahwa koleksi nyata kehidupan nyata selalu menerapkan beberapa bentuk berbagi dan menggunakan kembali untuk menghindari masalah yang Anda jelaskan. "Konkurensi" - argumen bermuara pada "Jika Anda ingin dapat berubah-ubah, maka objek yang tidak dapat diubah tidak berfungsi." Maksud saya, jika ada gagasan tentang "versi terbaru dari hal yang sama", maka sesuatu harus bermutasi, baik itu benda itu sendiri, atau sesuatu yang memiliki benda itu. Dan di "Storage", Anda tampaknya mengatakan bahwa mutabilitas kadang tidak diinginkan.
jhominal