Неизменный против неизменяемой коллекции - PullRequest
151 голосов
/ 17 января 2012

Из Обзора структуры коллекций :

Коллекции, которые не поддерживают операции модификации (такие как add, remove и clear), называются нередактируемым .Коллекции, которые не являются неизменяемыми, являются модифицируемыми .

Коллекции, которые дополнительно гарантируют, что никакие изменения в объекте Collection не будут видны, называются неизменяемыми .Коллекции, которые не являются неизменяемыми: изменяемые .

Я не могу понять различие.
В чем разница между неизменяемым и неизменным здесь?

Ответы [ 6 ]

191 голосов
/ 17 января 2012

Немодифицируемая коллекция часто является оболочкой для модифицируемой коллекции , к которой другой код может иметь доступ к . Таким образом, хотя вы не можете вносить в него какие-либо изменения, если у вас есть только ссылка на немодифицируемую коллекцию, вы не можете полагаться на то, что содержимое не меняется.

неизменяемая коллекция гарантирует, что ничто больше не сможет изменить коллекцию. Если он переносит изменяемую коллекцию, он удостоверяется, что никакой другой код не имеет доступа к этой изменяемой коллекции. Обратите внимание, что хотя никакой код не может изменить объекты, на которые ссылается коллекция, сами объекты могут все еще быть изменяемыми - создание неизменяемой коллекции StringBuilder каким-то образом не «замораживает» эти объекты.

По сути, разница в том, сможет ли другой код изменить коллекцию за вашей спиной.

83 голосов
/ 17 января 2012

В основном unModifiable Коллекция - это представление, поэтому косвенно оно все еще может быть «изменено» из некоторой другой ссылки, которая может быть изменена. Также как просто только для чтения другой коллекции, когда исходная коллекция изменяется, unModifiable Collection всегда будет отображаться с последними значениями.

Однако immutable Коллекция может рассматриваться как только для чтения копия другой коллекции и не может быть изменена. В этом случае при изменении исходной коллекции неизменяемая коллекция не отражает изменения

Вот тестовый сценарий для визуализации этой разницы.

@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());

}

выход

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]
--
11 голосов
/ 17 января 2012

Я думаю, что основное отличие состоит в том, что владелец изменяемой коллекции может захотеть предоставить доступ к коллекции к какому-либо другому коду, но предоставить доступ через интерфейс, который не позволяет другому коду изменять коллекцию (хотя резервирование этой способности к собственному коду). Таким образом, коллекция не является неизменной, но некоторым пользователям не разрешается изменять коллекцию.

В руководстве Oracle по Java Collection Wrapper сказано следующее (выделение добавлено):

Не подлежащие изменению оболочки имеют два основных назначения:

  • Чтобы сделать коллекцию неизменной после ее создания. В этом случае рекомендуется не сохранять ссылку на поддержку. коллекция. Это абсолютно гарантирует неизменность.
  • Разрешить определенным клиентам доступ только для чтения к вашим структурам данных. Вы сохраняете ссылку на резервную коллекцию, но рука ссылка на обертку. Таким образом, клиенты могут смотреть, но не изменить, пока вы сохраняете полный доступ .
2 голосов
/ 23 июля 2015

Цитировать Учебные руководства по Java ™ :

В отличие от оболочек синхронизации, которые добавляют функциональность к обернутой коллекции, неизменяемые оболочки убирают функциональность. В частности, они лишают возможности изменять коллекцию, перехватывая все операции, которые могли бы изменить коллекцию, и выбрасывая исключение UnsupportedOperationException . Немодифицируемые обертки имеют два основных назначения:

  • Чтобы сделать коллекцию неизменной после ее создания. В этом случае хорошей практикой является не сохранять ссылку на резервную коллекцию. Это абсолютно гарантирует неизменность.

  • Разрешить определенным клиентам доступ только для чтения к вашим структурам данных. Вы сохраняете ссылку на резервную копию, но раздаете ссылку на упаковщик. Таким образом, клиенты могут просматривать, но не изменять, пока вы поддерживаете полный доступ.

(акцент мой)

Это действительно подводит итог.

2 голосов
/ 25 марта 2015

Если мы говорим о JDK Unmodifiable* против гуавы Immutable*, на самом деле разница также в производительности . Неизменяемые коллекции могут быть как более быстрыми, так и более эффективными в использовании памяти, если они являются , а не оболочками для обычных коллекций (реализации JDK являются оболочками). Ссылаясь на команду гуавы :

JDK предоставляет методы Collections.unmodifiableXXX, но, по нашему мнению, это могут быть

<...>

  • неэффективно: структуры данных по-прежнему имеют все накладные расходы на изменяемые коллекции, включая одновременные проверки изменений, дополнительное пространство в хеш-таблицах и т. Д.
1 голос
/ 23 декабря 2014

Как отмечено выше, немодифицируемое не похоже на неизменяемое, потому что немодифицируемое собрание может быть изменено, если, например, немодифицируемая коллекция имеет базовую коллекцию делегатов, на которую ссылается какой-либо другой объект, и этот объект изменяет ее.

Что касается неизменности, это даже не очень четко определено. Однако обычно это означает, что объект «не изменится», но это необходимо определить рекурсивно. Например, я могу определить неизменяемый для классов, чьи переменные экземпляра являются примитивами и чьи методы не содержат аргументов и возвращают примитивы. Затем методы рекурсивно позволяют переменным экземпляра быть неизменными, а все методы содержат аргументы, которые являются неизменяемыми и возвращают неизменные значения. Методы должны гарантированно возвращать одно и то же значение с течением времени.

Предполагая, что мы можем это сделать, также существует концепт-потокобезопасный. И вы можете быть уверены, что неизменяемость (или неизменяемость во времени) также подразумевает безопасность потоков. Однако это не так , и это главное, что я здесь подчеркиваю, что еще не было отмечено в других ответах. Я могу создать неизменный объект, который всегда возвращает одинаковые результаты, но не является поточно-ориентированным. Чтобы увидеть это, предположим, что я создаю неизменную коллекцию, поддерживая добавления и удаления с течением времени. Теперь неизменяемая коллекция возвращает свои элементы, просматривая внутреннюю коллекцию (которая может изменяться со временем), а затем (внутренне) добавляя и удаляя элементы, которые были добавлены или удалены после создания коллекции. Ясно, что хотя коллекция всегда будет возвращать одни и те же элементы, она не является поточно-ориентированной, просто потому, что никогда не изменит значение.

Теперь мы можем определить неизменяемый объект как потокобезопасный, который никогда не изменится. Существуют рекомендации по созданию неизменяемых классов, которые обычно приводят к таким классам, однако следует помнить, что могут существовать способы создания неизменяемых классов, которые требуют внимания к безопасности потоков, например, как описано в примере коллекции «снимок» выше.

...