Копирование наборов Java

83

Есть ли способ скопировать TreeSet? То есть можно ли пойти

Set <Item> itemList;
Set <Item> tempList;

tempList = itemList;

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

SNpn
источник
8
tempList.addAll(itemList)
dhblah

Ответы:

156

Другой способ сделать это - использовать конструктор копирования :

Collection<E> oldSet = ...
TreeSet<E> newSet = new TreeSet<E>(oldSet);

Или создайте пустой набор и добавьте элементы:

Collection<E> oldSet = ...
TreeSet<E> newSet = new TreeSet<E>();
newSet.addAll(oldSet);

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


Обратите внимание, что результатом копирования Setявляется новый, Setсодержащий ссылки на объекты, которые являются элементами оригинала Set. Сами объекты элементов не копируются и не клонируются. Это соответствует способу работы CollectionAPI Java : они не копируют объекты элементов.

Стивен С
источник
7

В Java 8 вы можете использовать streamи collectдля копирования элементов:

Set<Item> newSet = oldSet.stream().collect(Collectors.toSet());

Или можете собрать в анкету ImmutableSet(если знаете, что набор не должен меняться):

Set<Item> newSet = oldSet.stream().collect(ImmutableSet.toImmutableSet());
Ёси Дахари
источник
8
Вы можете ... но конструктор копирования (и т. Д.) Должен быть более эффективным, если вы просто копируете коллекцию.
Stephen C
3

Конструктор копирования, предоставленный @Stephen C, - это то, что нужно, когда у вас есть Setсозданный вами (или когда вы знаете, откуда он). Когда он исходит от a Map.entrySet(), это будет зависеть от Mapиспользуемой вами реализации:

findbugs говорит

Метод entrySet () может возвращать представление базовой карты, в которой один объект Entry повторно используется и возвращается во время итерации. Начиная с Java 1.6, это сделали и IdentityHashMap, и EnumMap. При итерации по такой карте значение Entry действительно только до тех пор, пока вы не перейдете к следующей итерации. Если, например, вы попытаетесь передать такой entrySet методу addAll, все пойдет не так.

Как addAll()вызывается конструктором копирования, вы можете обнаружить, что у вас есть набор только из одной записи: последней.

Однако не все Mapреализации делают это, поэтому, если вы знаете, что ваша реализация безопасна в этом отношении, конструктор копирования определенно подходит. В противном случае вам придется создавать новые Entryобъекты самостоятельно:

Set<K,V> copy = new HashSet<K,V>(map.size());
for (Entry<K,V> e : map.entrySet())
    copy.add(new java.util.AbstractMap.SimpleEntry<K,V>(e));

Изменить: в отличие от тестов, которые я выполнил на Java 7 и Java 6u45 (спасибо Стивену С), комментарий findbugs больше не кажется подходящим. Это могло быть в более ранних версиях Java 6 (до u45), но мне нечего тестировать.

Матье
источник
1
Это основано на наблюдении? Если так, то это похоже на ошибку в addAllреализации. FWIW, все Mapреализации, которые я просмотрел, повторяют набор записей (на некотором уровне) и извлекают ключ и значение для каждого из них . Тот факт, что итератор набора записей может каждый раз возвращать один и тот же объект, не имеет значения. Единственный случай, который я заметил, отличался, EnumMapкогда сам конструктор копирования клонировал записи ... если исходная карта была файлом EnumMap.
Stephen C
1
@StephenC, похоже, ты прав: тесты, которые я сделал IdentityHashMap, не приводят к этой ошибке. Больше беспокоит то, что я тестировал его на Java 6u45, и никаких проблем не было. Я предполагаю, что это ошибка в findbugs (или JDK, на котором они основали свои правила ...). Отредактирую свой ответ.
Matthieu
3

Начиная с Java 10 :

Set<E> oldSet = Set.of();
Set<E> newSet = Set.copyOf(oldSet);

Set.copyOf()возвращает неизменяемый объект, Setсодержащий элементы данного Collection.

Данное Collectionне должно быть null, и оно не должно содержать каких - либо nullэлементов.

Александр Пирогов
источник
2

Java 8+ :

Set<String> copy = new HashSet<>(mySet); 
Дж. Доу
источник