Неизменяемые коллекции Java

Из документации Java 1.6 Collection Framework:

Коллекции, которые не поддерживают какие-либо операции модификации (такие как add, remove а также clear) называются неизменяемыми. [...] Коллекции, которые дополнительно гарантируют, что никакие изменения в объекте Collection никогда не будут видны, называются неизменяемыми.

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

Второй вопрос:
Для того чтобы коллекция была неизменной, как можно обеспечить предоставление указанных дополнительных гарантий? Если состояние элемента в коллекции обновляется потоком, достаточно ли для неизменности того, что эти обновления в состоянии не видны в потоке, содержащем неизменную коллекцию?

Для того чтобы коллекция была неизменной, как можно обеспечить предоставление указанных дополнительных гарантий?

7 ответов

Решение

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

Неизменяемые коллекции не могут быть изменены вообще - они не оборачивают другую коллекцию - у них есть свои собственные элементы.

Вот цитата из гуавы ImmutableList

В отличие от Collections.unmodifiableList(java.util.List<? extends T>), который представляет собой вид отдельной коллекции, которая все еще может измениться, экземпляр ImmutableList содержит свои личные данные и никогда не изменится.

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

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

например

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);
Collection<String> c1 = new ArrayList<String>();
c1.add("foo");
Collection<String> c2 = Collections.unmodifiableList(c1);

c1 является изменчивым (то есть ни неизменяемым, ни неизменным).
c2 не изменяемый: он не может быть изменен сам, но если позже я изменяю c1 тогда это изменение будет видно в c2,

Это потому что c2 это просто обертка вокруг c1 и не совсем независимая копия. Гуава обеспечивает ImmutableList интерфейс и некоторые реализации. Они работают, фактически создавая копию входных данных (если входные данные не являются неизменной коллекцией сами по себе).

По поводу вашего второго вопроса:

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

Теперь у java 9 есть фабричные методы для неизменного списка, набора, карты и карты. Вход.

В Java SE 8 и более ранних версиях мы можем использовать служебные методы класса Collections, такие как unmodifiableXXX, для создания объектов Immutable Collection.

Однако эти методы Collections.unmodifiableXXX очень утомительны и многословны. Чтобы преодолеть эти недостатки, корпорация Oracle добавила несколько служебных методов в интерфейсы List, Set и Map.

Теперь в java 9: ​​- интерфейсы List и Set имеют методы "of()" для создания пустых или непустых неизменяемых объектов List или Set, как показано ниже:

Пример пустого списка

List immutableList = List.of();

Пример непустого списка

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

Я считаю, что дело здесь в том, что даже если коллекция не изменяема, это не гарантирует, что она не может измениться. Возьмите, например, коллекцию, которая выселяет элементы, если они слишком стары. Unmodifiable просто означает, что объект, содержащий ссылку, не может ее изменить, а не то, что он не может измениться. Настоящим примером этого является Collections.unmodifiableList метод. Возвращает неизменяемое представление списка. Ссылка List, которая была передана в этот метод, все еще может быть изменена, и поэтому список может быть изменен любым держателем переданной ссылки. Это может привести к ConcurrentModificationExceptions и другим плохим вещам.

Неизменный, означает, что никоим образом нельзя изменить коллекцию.

Второй вопрос: Неизменяемая коллекция не означает, что объекты, содержащиеся в коллекции, не изменятся, просто эта коллекция не изменится в количестве и составе объектов, которые она содержит. Другими словами, список ссылок коллекции не изменится. Это не означает, что внутренности объекта, на который ссылаются, не могут измениться.

Pure4J поддерживает то, что вам нужно, двумя способами.

Во-первых, это обеспечивает @ImmutableValue аннотации, так что вы можете аннотировать класс, чтобы сказать, что он неизменен. Существует плагин maven, который позволяет вам проверить, что ваш код на самом деле неизменен (использование final так далее.).

Во-вторых, он предоставляет постоянные коллекции из Clojure (с добавленными обобщениями) и гарантирует, что элементы, добавленные в коллекции, являются неизменяемыми. Производительность этих, видимо, довольно хорошая. Все коллекции являются неизменяемыми, но реализуют интерфейсы Java-коллекций (и обобщения) для проверки. Мутация возвращает новые коллекции.

Отказ от ответственности: я разработчик этого

До Java 9 методы Collections.unmodifiableXXX() использовались для создания неизменяемых коллекций. Эти методы просто ведут себя как методы-оболочки, которые возвращают неизменяемое представление или представление только для чтения исходной коллекции. т.е. вы не можете выполнять операции модификации, такие как добавление, удаление, замена, очистка и т. д., через ссылки, возвращаемые этими методами-оболочками. Но вы можете изменить исходную коллекцию, если у вас есть другие ссылки на нее, и эти изменения будут отражены в представлении, возвращаемом этими методами.

Например,

      import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
 
public class Java9ImmutableCollections 
{
    public static void main(String[] args) 
    {
        List<String> sportList = new ArrayList<String>();
         
        sportList.add("Hockey");
        sportList.add("Cricket");
        sportList.add("Tennis");
         
        List<String> unModifiableSportList = Collections.unmodifiableList(sportList);
 
        System.out.println(sportList);    //Output : [Hockey, Cricket, Tennis]
         
        System.out.println(unModifiableSportList);    //Output : [Hockey, Cricket, Tennis]
         
        unModifiableSportList.add("Wrestling");     //It gives run-time error
         
        sportList.add("Kabaddi");      //It gives no error and will be reflected in unModifiableSportList
         
        System.out.println(sportList);    //Output : [Hockey, Cricket, Tennis, Kabaddi]
         
        System.out.println(unModifiableSportList);    //Output : [Hockey, Cricket, Tennis, Kabaddi]
         
    }
}

Начиная с Java 9, для создания неизменяемых коллекций вводятся статические фабричные методы.

      1) Immutable List : List.of()
2) Immutable Set : Set.of()
3) Immutable Map : Map.of() or Map.ofEntries()

Неизменяемый против неизменяемого:

Неизменяемые коллекции Java 9 и неизменяемые коллекции, возвращаемые методами-оболочками Collections.unmodifiedXXX(), не совпадают. Неизменяемые коллекции — это просто представления исходной коллекции, доступные только для чтения. Вы можете выполнять операции изменения исходной коллекции, и эти изменения будут отражены в коллекциях, возвращаемых этими методами. Но неизменяемые коллекции, возвращаемые статическими фабричными методами Java 9, являются неизменяемыми на 100%. Вы не можете изменить их после того, как они созданы.

Источник: https://javaconceptoftheday.com/java-9-immutable-collections/

Другие вопросы по тегам