Java Immutable Collections


115

Gönderen Java 1.6 Koleksiyonu Çerçeve belgeler :

Herhangi bir değişiklik işlemleri (örneğin desteklemeyen Koleksiyonları add, removeve clear) olarak adlandırılır değiştirilemez . [...] Ek olarak Koleksiyon nesnesinde hiçbir değişikliğin görünür olmayacağını garanti eden koleksiyonlar, değişmez olarak adlandırılır .

İkinci kriter kafamı biraz karıştırıyor. İlk koleksiyon değiştirilemez olduğu ve orijinal koleksiyon referansının elden çıkarıldığı varsayıldığında, ikinci satırda atıfta bulunulan değişiklikler nelerdir? Koleksiyonda tutulan öğelerdeki değişikliklere, yani öğelerin durumuna mı atıfta bulunuyor?

İkinci soru:
Bir koleksiyonun değişmez olması için, belirtilen ek garantilerin sağlanması nasıl yapılır? Koleksiyondaki bir öğenin durumu bir iş parçacığı tarafından güncellenirse, durumdaki bu güncellemelerin değişmez koleksiyonu tutan iş parçacığında görünmemesi değişmezlik için yeterli midir?

Bir koleksiyonun değişmez olması için, belirtilen ek garantilerin sağlanması nasıl yapılır?


Genel olarak (özellikle işlevsel dillerde), değişmez (diğer adıyla kalıcı) koleksiyon, bu koleksiyonun yeni durumunu alabileceğiniz anlamında değişebilir, ancak aynı zamanda eski durum diğer bağlantılardan hala erişilebilir olacaktır. Örneğin, newCol = oldCol.add("element")1 eleman daha eski olanın kopyası olan yeni koleksiyon üretecek ve tüm referanslar oldColaynı değişmemiş eski koleksiyona işaret edecektir.
ffriend

Yanıtlar:


154

Değiştirilemez koleksiyonlar genellikle diğer koleksiyonların salt okunur görünümleridir (sarmalayıcılar). Bunları ekleyemez, kaldıramaz veya temizleyemezsiniz, ancak temel koleksiyon değişebilir.

Değişmez koleksiyonlar hiçbir şekilde değiştirilemez - başka bir koleksiyonu sarmazlar - kendi öğelerine sahiptirler.

İşte guava'dan bir alıntı ImmutableList

Collections.unmodifiableList(java.util.List<? extends T>)Hala değişebilen ayrı bir koleksiyonun görünümü olan aksine , bir örneği ImmutableListkendi özel verilerini içerir ve asla değişmez.

Yani, temelde, değişken bir koleksiyondan değişmez bir koleksiyon elde etmek için, öğelerini yeni koleksiyona kopyalamanız ve tüm işlemlere izin vermemeniz gerekir.


@Bhaskar - son paragrafıma bakın.
Bozho

1
başka bir değiştirilemez koleksiyonun içine sarılmış koleksiyonun başka bir referansı yoksa, değiştirilemeyen koleksiyonun baharı, değişmez bir koleksiyonla tamamen aynı mıdır?
Bhaskar

1
@Bozho, Destek koleksiyonuna referans sağlanmadıysa ve yalnızca değiştirilemez koleksiyon sarmalayıcı referansı sağlandıysa, onu değiştirmenin bir yolu yoktur. O zaman neden "Emin olamıyorsun" diyorsun? Destek koleksiyonu değiştirilebilir olduğu için bazı iş parçacığı veya bir şekilde değiştirildiği bir senaryoya mı işaret ediyor?
AKS

@AKS: Bir koleksiyon sarmalandığında unmodifiableList, yalnızca bu listeye bir referans alan kod onu değiştiremez, ancak orijinal listeye referansı olan ve sarmalayıcı oluşturulmadan önce onu değiştirebilen herhangi bir kod hala bunu daha sonra yapabileceksiniz. Orijinal listeyi oluşturan kod, şimdiye kadar var olan her referansa ne olduğunu biliyorsa ve hiçbirinin listeyi değiştirebilecek kodun eline geçmeyeceğini biliyorsa, o zaman listenin asla olmayacağını bilebilir. değiştirilmiş. Referans dış koddan
alınmışsa

... unmodifiableListonu kullanan herhangi bir kodun paketlenmiş koleksiyonun değişip değişmeyeceğini veya nasıl değişeceğini bilmesinin bir yolu yoktur .
supercat

86

Aradaki fark, değişikliklere izin veren değişmez bir koleksiyona referansınız olmamasıdır. Değiştirilemez koleksiyonlar bu referansla değiştirilemez , ancak başka bir nesne, değiştirilebileceği aynı verilere işaret edebilir.

Örneğin

List<String> strings = new ArrayList<String>();
List<String> unmodifiable = Collections.unmodifiableList(strings);
unmodifiable.add("New string"); // will fail at runtime
strings.add("Aha!"); // will succeed
System.out.println(unmodifiable);

1
Orijinal koleksiyon referansının temeldeki koleksiyonu değiştirmek için kullanılmaması koşuluyla, hangi çeşitli nedenler, bir koleksiyonda değiştirilemez bir değişiklik getirebilir?
Bhaskar

21
Collection<String> c1 = new ArrayList<String>();
c1.add("foo");
Collection<String> c2 = Collections.unmodifiableList(c1);

c1olan değişken (yani ne unmodifiable ne de değişmez ).
c2olduğunu unmodifiable : kendi kendine değiştirilemez, ama değişmek daha sonra ise c1o zaman bu değişim görünür olacaktır c2.

Bunun nedeni c2, basitçe bir sarmalayıcı olması c1ve gerçekten bağımsız bir kopya olmamasıdır. Guava ImmutableListarayüzü sağlar ve bazı uygulamaları sağlar. Bunlar aslında girdinin bir kopyasını oluşturarak çalışır (girdi kendi başına değişmez bir koleksiyon olmadığı sürece).

İkinci sorunuzla ilgili olarak:

Bir koleksiyonun değişkenliği / değişmezliği, içinde yer alan nesnelerin değişkenliğine / değişmezliğine bağlı değildir . Bir koleksiyonda yer alan bir nesneyi değiştirme yok değil bu açıklama için bir "toplama modifikasyonu" olarak sayılır. Elbette değişmez bir koleksiyona ihtiyacınız varsa, genellikle onun değişmez nesneler içermesini de istersiniz.


2
@John: hayır, değil. En azından OP tarafından alıntılanan tanıma göre değil.
Joachim Sauer

@JohnVint, gerçekten mi? Ben öyle düşünmüyorum, çünkü c1'i kullanarak hala ona eleman ekleyebiliyorum ve bu ekleme c2 tarafından görülebilecek. Bu onun değişmez olmadığı anlamına gelmez mi?
Bhaskar

Sanırım c1 kaçabilirse, o zaman değişmez olmazdı, ancak değişmezlik aynı zamanda koleksiyondaki içeriği de ifade eder. Ben daha çok değiştirilemez bir java.util.Date Koleksiyonundan bahsediyordum
John Vint

1
@Vint: "eğer kaçmazsa" c1, spesifikasyonun herhangi bir yerinde ayırt edilen bir değerlendirme değildir. Bence, eğer sen yapabilirsiniz dışı değişmez kılan bir şekilde toplanmasını kullanmak, o zaman gerektiğini hep dışı değişmez düşünün.
Joachim Sauer

1
Tanımı alıntı yapmama izin verin: "Ek olarak garanti eden koleksiyonlar ..." (vurgu benimkidir). Collection.unmodifiableList() olamaz onun argüman kaçış olmadığını garanti edemez, çünkü garanti. Guava , argümanlarının kaçmasına izin verseniz bile, ImmutableList.of daima bir değişmez üretir List.
Joachim Sauer

17

Artık java 9 , Değişmez Liste, Küme, Harita ve Harita için fabrika Yöntemlerine sahiptir.

Java SE 8 ve önceki sürümlerinde, Immutable Collection nesneleri oluşturmak için unmodifiableXXX gibi Collections sınıfı yardımcı program yöntemlerini kullanabiliriz.

Ancak bu Collections.unmodifiableXXX yöntemleri çok sıkıcı ve ayrıntılı bir yaklaşımdır. Oracle Corp, bu eksikliklerin üstesinden gelmek için List, Set ve Map arayüzlerine birkaç yardımcı yöntem ekledi.

Şimdi java 9'da: - List ve Set arayüzleri, aşağıda gösterildiği gibi boş veya boş olmayan bir Değişmez Liste veya Set nesneleri oluşturmak için “of ()” yöntemlerine sahiptir:

Boş Liste Örneği

List immutableList = List.of();

Boş Olmayan Liste Örneği

List immutableList = List.of("one","two","three");

2
Ve Java 10'da List.copyOfve Set.copyOfbir liste / kümenin değiştirilemez bir kopyasını oluşturmaya izin veren veya zaten değiştirilemezse verilen koleksiyonu geri veren eklenmiş olanlar
bkz.JDK

6

Buradaki mesele şu ki, bir koleksiyon Değiştirilemez olsa bile, bu onun değişemeyeceğini garanti etmez. Örneğin, öğeleri çok eskiyse çıkaran bir koleksiyonu ele alalım. Değiştirilemez sadece referansı tutan nesnenin onu değiştiremeyeceği, değiştiremeyeceği anlamına gelir. Bunun gerçek bir örneği Collections.unmodifiableListyöntemdir. Bir Listenin değiştirilemez bir görünümünü döndürür. Bu yönteme aktarılan Liste referansı hala değiştirilebilir ve bu nedenle liste, geçirilen referansın herhangi bir sahibi tarafından değiştirilebilir. Bu ConcurrentModificationExceptions ve diğer kötü şeylere neden olabilir.

Değişmez, koleksiyonun hiçbir şekilde değiştirilemeyeceği anlamına gelir.

İkinci soru: Bir Immutable koleksiyon, koleksiyonun içerdiği nesnelerin değişmeyeceği anlamına gelmez, sadece bu koleksiyonun tuttuğu nesnelerin sayısı ve kompozisyonunda değişmeyeceği anlamına gelir. Başka bir deyişle, koleksiyonun referans listesi değişmeyecektir. Bu, referans verilen nesnenin iç kısımlarının değişemeyeceği anlamına gelmez.


İyi bir!! Bu yüzden, Değiştirilemez Koleksiyon üzerinde bir sarmalayıcı oluşturursam ve değiştirilebilir koleksiyon referansını özel olarak yaparsam, bunun değişmez olduğundan emin olabilirim. sağ?
AKS

Sorunuzu anlarsam, cevap hayırdır. Değiştirilemez olanı sarmak, onu koleksiyonun unmodifiableListdeğiştirilmişe geçirilmesini önlemek için hiçbir şey yapmaz . Bunu yapmak istiyorsanız kullanın ImmutableList.
John B

0

Pure4J , peşinde olduğunuz şeyi iki şekilde destekler.

İlk olarak, @ImmutableValuebir sınıfa onun değişmez olduğunu söylemek için not ekleyebilmeniz için bir açıklama sağlar. Kodunuzun gerçekten değişmez olduğunu (kullanımı finalvb.) Kontrol etmenize izin veren bir maven eklentisi vardır .

İkinci olarak, Clojure'dan kalıcı koleksiyonlar sağlar (ek jeneriklerle) ve koleksiyonlara eklenen öğelerin değişmez olmasını sağlar. Bunların performansı görünüşe göre oldukça iyi. Koleksiyonların tümü değişmezdir, ancak inceleme için java koleksiyon arayüzleri (ve jenerikler) uygular. Mutasyon yeni koleksiyonlar döndürür.

Feragatname: Bunun geliştiricisiyim

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.