Как вернуть потокобезопасную / неизменяемую коллекцию в Java? - PullRequest
7 голосов
/ 12 июля 2011

В проекте, который я пишу, мне нужно вернуть потокобезопасное и неизменное представление из функции.Тем не менее, я не уверен в этом.Поскольку synchronizedList и unmodifiableList просто возвращают представления списка, я не знаю, справится ли

Collections.synchronizedList(Collections.unmodifiableList(this.data));

.

Может кто-нибудь сказатьмне, если это правильно, а если нет, есть ли ситуации, в которых это может произойти?

Спасибо за любые входные данные!

Ответы [ 4 ]

13 голосов
/ 12 июля 2011

Я считаю, что это настоящий пробел в JDK.К счастью, команда Google, возглавляемая дизайнером Java Collections Джошуа Блохом , создала библиотеку , которая включает в себя действительно неизменные коллекции.

ImmutableList В частности, это реализация, которую вы ищете. Здесь - это быстрый набросок некоторых функций ImmutableCollections Guava.

5 голосов
/ 12 июля 2011

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

Лучше всего проверить исходный код, когда есть такие вопросы. Похоже, он возвращает UnmodifiableList:

/**
 * @serial include
 */
static class UnmodifiableList<E> extends UnmodifiableCollection<E>
                  implements List<E> {
    static final long serialVersionUID = -283967356065247728L;
final List<? extends E> list;

UnmodifiableList(List<? extends E> list) {
    super(list);
    this.list = list;
}

public boolean equals(Object o) {return o == this || list.equals(o);}
public int hashCode()       {return list.hashCode();}

public E get(int index) {return list.get(index);}
public E set(int index, E element) {
    throw new UnsupportedOperationException();
    }
public void add(int index, E element) {
    throw new UnsupportedOperationException();
    }
public E remove(int index) {
    throw new UnsupportedOperationException();
    }
public int indexOf(Object o)            {return list.indexOf(o);}
public int lastIndexOf(Object o)        {return list.lastIndexOf(o);}
public boolean addAll(int index, Collection<? extends E> c) {
    throw new UnsupportedOperationException();
    }
public ListIterator<E> listIterator()   {return listIterator(0);}

public ListIterator<E> listIterator(final int index) {
    return new ListIterator<E>() {
    ListIterator<? extends E> i = list.listIterator(index);

    public boolean hasNext()     {return i.hasNext();}
    public E next()          {return i.next();}
    public boolean hasPrevious() {return i.hasPrevious();}
    public E previous()      {return i.previous();}
    public int nextIndex()       {return i.nextIndex();}
    public int previousIndex()   {return i.previousIndex();}

    public void remove() {
        throw new UnsupportedOperationException();
            }
    public void set(E e) {
        throw new UnsupportedOperationException();
            }
    public void add(E e) {
        throw new UnsupportedOperationException();
            }
    };
}
4 голосов
/ 02 марта 2016
Collections.unmodifiableList(this.data) 

Сделаем, так как вернет вид. Любые попытки модификации в этом представлении приведут к выбрасыванию UnsupportedOperationException. Ниже приведены выдержки из Collections#unmodifiableList документации.

Возвращает неизменяемое представление указанного списка. Этот метод позволяет модулям предоставлять пользователям доступ «только для чтения» к внутренним спискам. Операции запроса в возвращаемом списке, «прочитанные» в указанный список, и попытки изменить возвращенный список, будь то прямой или через его итератор, приводят к UnsupportedOperationException.

......

java 8 java.util.Collections javadoc

0 голосов
/ 06 ноября 2015

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

Чтобы решить эту проблему, вам нужно использовать неизменяемые коллекции и неизменные элементы. Затем в результате возникает потокобезопасность.

Clojure содержит такие неизменные (или постоянные) коллекции .

Проще говоря, добавление или удаление новых элементов возвращает новую коллекцию, которая, как правило, действительно повторно использует большие части старой коллекции посредством умного использования структур данных типа Trie.

Сами по себе они плохо подходят для использования на прямой Java.

Pure4j - это попытка перенести их (и стиль, основанный на неизменяемости / значениях, поддерживаемый Clojure) на язык Java. Это может быть то, что вы ищете.

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

...