Değiştirilemez ve değiştirilemez koleksiyon


170

Gönderen Koleksiyonları Çerçeve Bakış :

Modifikasyon işlemlerini desteklememektedir takımları (örneğin add, removeve clear) olarak adlandırılır değiştirilemez . Değiştirilemeyen koleksiyonlar değiştirilebilir .

Ek olarak, Collectionnesnede hiçbir değişikliğin görünmeyeceğini garanti eden koleksiyonlara değişmez denir . Değişmez koleksiyonlar değiştirilebilir .

Ayrımı anlayamıyorum. Burada değiştirilemez ve değişmez
arasındaki fark nedir ?

Yanıtlar:


207

Değiştirilemez bir koleksiyon, genellikle diğer kodun hala erişebileceği değiştirilebilir bir koleksiyonun etrafındaki bir paketleyicidir . Yani iken sen sadece unmodifiable koleksiyonuna bir başvuru varsa Bunda herhangi bir değişiklik yapamazsınız, sen değiştirmiyor içeriğine güvenemez.

Bir değişmez toplama garanti o şey artık toplama değiştirebilir. Değiştirilebilir bir koleksiyonu sararsa, değiştirilebilen koleksiyona başka hiçbir kodun erişememesini sağlar. Hiçbir kod koleksiyonun hangi nesnelere referans içerdiğini değiştiremese de, nesnelerin kendileri hala değişebilir olabilir - değişmez bir koleksiyon oluşturmak bir StringBuilderşekilde bu nesneleri "dondurmaz".

Temel olarak, fark diğer kodların koleksiyonu arkanızdan değiştirip değiştiremeyeceği ile ilgilidir.


64
Değişmez bir koleksiyon artık hiçbir şeyin değişmeyeceğini garanti etmez . Sadece koleksiyonun kendisinin değiştirilememesini sağlar (ve sararak değil kopyalayarak). Koleksiyonda bulunan nesneler hala değiştirilebilir ve bunlara hiçbir garanti verilmez.
Hiery Nomus

8
@HieryNomus: Hiçbir şeyin değişemeyeceğini söylemedim - hiçbir şeyin koleksiyonu değiştiremeyeceğini söyledim.
Jon Skeet

1
Tamam, bunu yanlış okuyabilirdim;) Ama yine de açıklığa kavuşturmak iyidir.
Hiery Nomus

5
Yani, ne diyorsun. Gerçek değişmezlik için, değişmez tipte öğeler içeren değişmez bir koleksiyona ihtiyacınız var.
Evan Plaice

1
@savanibharat: Bu, yine de değiştirilebilecek herhangi bir kod yolu olup olmadığına bağlıdır list. Bir şey daha sonra arayabilirse list.add(10)o collzaman bu değişikliği yansıtacaktır, bu yüzden hayır, değişmez olarak adlandırmam.
Jon Skeet

92

Temel olarak unModifiableKoleksiyon bir görünümdür, dolaylı olarak değiştirilebilen başka bir referanstan 'değiştirilebilir' olabilir. Ayrıca , annother koleksiyonunun salt okunur bir görünümü olarak, Kaynak koleksiyonu değiştiğinde Değiştirilemez Koleksiyon her zaman en son değerlerle sunulacaktır.

Ancak immutableKoleksiyon, başka bir koleksiyonun salt okunur bir kopyası olarak kabul edilebilir ve değiştirilemez. Bu durumda kaynak koleksiyonu değiştiğinde, değişmez Koleksiyon değişiklikleri yansıtmaz

İşte bu farkı görselleştirmek için bir testcase.

@Test
public void testList() {

    List<String> modifiableList = new ArrayList<String>();
    modifiableList.add("a");

    System.out.println("modifiableList:"+modifiableList);
    System.out.println("--");


    //unModifiableList

    assertEquals(1, modifiableList.size());

    List<String> unModifiableList=Collections.unmodifiableList(
                                        modifiableList);

    modifiableList.add("b");

    boolean exceptionThrown=false;
    try {
        unModifiableList.add("b");
        fail("add supported for unModifiableList!!");
    } catch (UnsupportedOperationException e) {
        exceptionThrown=true;
        System.out.println("unModifiableList.add() not supported");
    }
    assertTrue(exceptionThrown);

    System.out.println("modifiableList:"+modifiableList);
    System.out.println("unModifiableList:"+unModifiableList);

    assertEquals(2, modifiableList.size());
    assertEquals(2, unModifiableList.size());
            System.out.println("--");



            //immutableList


    List<String> immutableList=Collections.unmodifiableList(
                            new ArrayList<String>(modifiableList));

    modifiableList.add("c");

    exceptionThrown=false;
    try {
        immutableList.add("c");
        fail("add supported for immutableList!!");
    } catch (UnsupportedOperationException e) {
        exceptionThrown=true;
        System.out.println("immutableList.add() not supported");
    }
    assertTrue(exceptionThrown);


    System.out.println("modifiableList:"+modifiableList);
    System.out.println("unModifiableList:"+unModifiableList);
    System.out.println("immutableList:"+immutableList);
    System.out.println("--");

    assertEquals(3, modifiableList.size());
    assertEquals(3, unModifiableList.size());
    assertEquals(2, immutableList.size());

}

Çıktı

modifiableList:[a]
--
unModifiableList.add() not supported
modifiableList:[a, b]
unModifiableList:[a, b]
--
immutableList.add() not supported
modifiableList:[a, b, c]
unModifiableList:[a, b, c]
immutableList:[a, b]
--

Herhangi bir fark göremiyorum, lütfen Dokunulmaz'ın farklı olduğunu gösterebilir misiniz? Hem Bağlanabilir hem de değiştirilemez hata atıyor ve ekleme desteklenmiyor görebilirsiniz. Burada bir şey mi eksik?
AKS

2
@AKS listeye 'c' eklenmesinden sonra son üç liste girişlerinin çıktısını bakınız her iki boyutu ise modifiableListve unModifiableListartmıştır immutableListboyutu değişmedi
Prashant Bhate

1
Ah! anladım! :) .. Yani burada değiştirilemezListeki değişiklikleri kullanarak değiştirilmemişList değiştirdiniz, ancak ImmutableList değiştirilemez. Ancak aynı şekilde ImmutableList'i de değiştirebilirsiniz, burada istemci sadece ImmutableList referansına erişebilecek, ImmutableList'in oluşturulduğu kullanarak modifiableList'e referansın istemciye maruz kalmayacağını düşünüyorum. sağ?
AKS

1
evet çünkü new ArrayList<String>(modifiableList)immutableList referansı değiştirilemez
Prashant Bhate

@PrashantBhate Merhaba, new ArrayList<String>(modifiableList)nedeniyle referans yok new? Teşekkürler.
Unheilig

11

Temel fark, değişken bir koleksiyonun sahibinin koleksiyona başka bir koda erişim sağlamak isteyebileceğini, ancak diğer kodların koleksiyonu değiştirmesine izin vermeyen bir arabirim aracılığıyla bu erişimi sağlaması isteyebileceğidir (bu özelliği saklı tutarken) (sahip olma koduna). Bu nedenle koleksiyon değiştirilemez, ancak bazı kullanıcıların koleksiyonu değiştirmesine izin verilmez.

Oracle'ın Java Collection Wrapper öğreticisinde şunları söyleyebiliriz (vurgu eklendi):

Değiştirilemeyen ambalajların aşağıdaki gibi iki ana kullanımı vardır:

  • Bir koleksiyon oluşturulduktan sonra değişmez hale getirmek. Bu durumda, destek koleksiyonuna referans vermemek iyi bir uygulamadır. Bu kesinlikle değişmezliği garanti eder.
  • Belirli istemcilerin veri yapılarınıza salt okunur erişmesine izin vermek için. Destek koleksiyonuna bir başvuru tutarsınız, ancak sarmalayıcıya bir başvuru dağıtırsınız. Bu şekilde, tam erişimi korurken istemciler görünebilir ancak değiştirilemez .

3

JDK Unmodifiable*vs guava hakkında konuşuyorsak Immutable*, aslında fark da performanstadır . Değişmez koleksiyonlar, normal koleksiyonların etrafına paketleyici değilse (JDK uygulamaları paketleyicidir) hem daha hızlı hem de bellek açısından daha verimli olabilir . Guava ekibine atıfta bulunmak :

JDK Collections.unmodifiableXXX yöntemleri sağlar, ancak bizce bunlar olabilir

<...>

  • verimsiz: veri yapıları, eşzamanlı modifikasyon kontrolleri, hash tablolarında ekstra alan vb.

performans düşünülürse, değiştirilemez bir sargının koleksiyonu kopyalamamasını da dikkate almalısınız, burada guava'da ve şimdi de jdk9 + 'da kullanılan değişmez sürüm, örneğin List.of(...)iki kez kopyalanır!
benez

2

Java ™ Eğiticilerini alıntılamak için :

Sarılı koleksiyona işlevsellik katan senkronizasyon sarmalayıcılarının aksine, değiştirilemeyen sarmalayıcılar işlevselliği ortadan kaldırır. Özellikle, koleksiyonu değiştirecek tüm işlemleri kesip bir UnsupportedOperationException kurarak koleksiyonu değiştirme yeteneğini ortadan kaldırırlar . Değiştirilemeyen ambalajların aşağıdaki gibi iki ana kullanımı vardır:

  • Bir koleksiyon oluşturulduktan sonra değişmez hale getirmek. Bu durumda, destek koleksiyonuna referans vermemek iyi bir uygulamadır. Bu kesinlikle değişmezliği garanti eder.

  • Belirli istemcilerin veri yapılarınıza salt okunur erişmesine izin vermek için. Destek koleksiyonuna bir başvuru tutarsınız, ancak sarmalayıcıya bir başvuru dağıtırsınız. Bu şekilde, tam erişimi korurken istemciler görünebilir ancak değiştirilemez.

(benimkini vurgula)

Bu gerçekten özetliyor.


1

Yukarıda belirtildiği gibi değiştirilemez değişmez gibi değildir, çünkü değiştirilemez bir koleksiyon, örneğin değiştirilemez bir koleksiyonun, başka bir nesne tarafından referans verilen ve bu nesne tarafından değiştirildiği bir delege koleksiyonuna sahipse değiştirilebilir.

Değişmez ile ilgili olarak, iyi tanımlanmamıştır. Bununla birlikte, bu genellikle nesnenin "değişmeyeceği" anlamına gelir, ancak bunun özyinelemeli olarak tanımlanması gerekir. Örneğin, örnek değişkenleri tüm ilkel olan ve yöntemleri hiçbir argüman ve dönüş ilkel içermeyen sınıflarda değişmez tanımlayabilirim. Daha sonra yöntemler özyinelemeli olarak örnek değişkenlerinin değiştirilemez olmasına ve tüm yöntemlerin değiştirilemez ve değiştirilemez değerler döndüren bağımsız değişkenler içermesine izin verir. Yöntemlerin aynı değeri zaman içinde döndüreceği garanti edilmelidir.

Bunu yapabileceğimizi varsayarsak, iş parçacığı için güvenli bir kavram da vardır. Ve değişmez (ya da zaman içinde değiştirilemez) de iplik güvenliğini ima ettiğine inanabilirsiniz. Ancak durum böyle değilve burada yaptığım ana nokta, diğer cevaplarda henüz belirtilmemiş. Her zaman aynı sonuçları döndüren ancak iş parçacığı güvenli olmayan değişmez bir nesne inşa edebilirim. Bunu görmek için zaman içinde eklemeler ve silmeler yaparak değişmez bir koleksiyon oluşturduğumu varsayalım. Şimdi değiştirilemez koleksiyon, iç koleksiyona (zaman içinde değişebilir) baktıktan sonra (dahili olarak) koleksiyonun oluşturulmasından sonra eklenen veya silinen öğeleri ekleyerek ve silerek öğelerini döndürür. Açıkçası, koleksiyon her zaman aynı öğeleri döndürse de, yalnızca değeri değişmeyeceği için yalnızca iş parçacığı için güvenli değildir.

Şimdi değişmez olanı, iş parçacığı güvenli olan ve asla değişmeyen nesneler olarak tanımlayabiliriz. Genellikle bu tür sınıflara götüren değişmez sınıflar oluşturmaya yönelik yönergeler vardır, ancak, örneğin yukarıdaki "anlık görüntü" toplama örneğinde açıklandığı gibi, iplik güvenliğine dikkat gerektiren değişmez sınıflar oluşturmanın yolları olabileceğini unutmayın.


1

Java ™ Eğiticileri şunları söylüyor:

Sarılı koleksiyona işlevsellik katan senkronizasyon sarmalayıcılarının aksine, değiştirilemeyen sarmalayıcılar işlevselliği ortadan kaldırır. Özellikle, koleksiyonu değiştirecek tüm işlemleri kesip bir UnsupportedOperationException kurarak koleksiyonu değiştirme yeteneğini ortadan kaldırırlar. Değiştirilemeyen ambalajların aşağıdaki gibi iki ana kullanımı vardır:

Bir koleksiyon oluşturulduktan sonra değişmez hale getirmek. Bu durumda, destek koleksiyonuna referans vermemek iyi bir uygulamadır. Bu kesinlikle değişmezliği garanti eder.

Belirli istemcilerin veri yapılarınıza salt okunur erişmesine izin vermek için. Destek koleksiyonuna bir başvuru tutarsınız, ancak sarmalayıcıya bir başvuru dağıtırsınız. Bu şekilde, tam erişimi korurken istemciler görünebilir ancak değiştirilemez.

Farkı anlamak için yeterince iyi bir açıklama olduğunu düşünüyorum.

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.