Перейти к основному содержимому

Скопируйте список в другой список в Java

· 4 мин. чтения

1. Обзор

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

Для ознакомления с использованием коллекций см . эту статью здесь .

2. Конструктор

Простой способ скопировать список — использовать конструктор, который принимает коллекцию в качестве аргумента:

List<Plant> copy = new ArrayList<>(list);

Поскольку здесь мы копируем ссылки, а не клонируем объекты, каждое исправление, сделанное в одном элементе, повлияет на оба списка.

Таким образом, хорошо использовать конструктор для копирования неизменяемых объектов:

List<Integer> copy = new ArrayList<>(list);

Integer — неизменяемый класс; его значение устанавливается при создании экземпляра и никогда не может измениться.

Таким образом, ссылка Integer может совместно использоваться несколькими списками и потоками, и никто не может изменить ее значение.

3. Список ConcurrentAccessException

Распространенной проблемой при работе со списками является ConcurrentAccessException . Обычно это означает, что мы изменяем список, когда пытаемся его скопировать, скорее всего, в другом потоке.

Чтобы решить эту проблему, мы должны:

  • Используйте коллекцию, предназначенную для одновременного доступа
  • Заблокируйте коллекцию соответствующим образом, чтобы перебрать ее
  • Найдите способ избежать копирования оригинальной коллекции

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

Для получения дополнительной информации, пожалуйста, обратитесь к этой статье .

Если мы хотим заблокировать Collection , можно использовать примитив блокировки для сериализованного доступа для чтения/записи, например ReentrantReadWriteLock .

4. Добавить все

Другой подход к копированию элементов — использование метода addAll :

List<Integer> copy = new ArrayList<>();
copy.addAll(list);

При использовании этого метода важно помнить, что, как и в случае с конструктором, содержимое обоих списков будет ссылаться на одни и те же объекты.

5. Коллекции.copy

Класс Collections состоит исключительно из статических методов, которые работают с коллекциями или возвращают их.

Одним из них является copy , для которого требуется исходный список и целевой список, длина которого не меньше исходного.

Он будет поддерживать индекс каждого скопированного элемента в списке назначения, например оригинала:

List<Integer> source = Arrays.asList(1,2,3);
List<Integer> dest = Arrays.asList(4,5,6);
Collections.copy(dest, source);

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

Если размер списка назначения больше, чем размер источника:

List<Integer> source = Arrays.asList(1, 2, 3);
List<Integer> dest = Arrays.asList(5, 6, 7, 8, 9, 10);
Collections.copy(dest, source);

Здесь только первые три элемента были перезаписаны, а остальные элементы в списке сохранены.

6. Использование Java 8

Эта версия Java расширяет наши возможности, добавляя новые инструменты. В следующих примерах мы рассмотрим Stream :

List<String> copy = list.stream()
.collect(Collectors.toList());

Главное преимущество этого варианта — возможность использовать пропуск и фильтры. В следующем примере мы пропустим первый элемент:

List<String> copy = list.stream()
.skip(1)
.collect(Collectors.toList());

Также можно фильтровать по длине строки или сравнивать атрибуты наших объектов:

List<String> copy = list.stream()
.filter(s -> s.length() > 10)
.collect(Collectors.toList());
List<Flower> flowers = list.stream()
.filter(f -> f.getPetals() > 6)
.collect(Collectors.toList());

Вероятно, мы хотим работать нулевым безопасным способом:

List<Flower> flowers = Optional.ofNullable(list)
.map(List::stream)
  .orElseGet(Stream::empty)
  .collect(Collectors.toList());

Вероятно, мы также захотим пропустить элемент таким образом:

List<Flower> flowers = Optional.ofNullable(list)
  .map(List::stream).orElseGet(Stream::empty)
  .skip(1)
  .collect(Collectors.toList());

7. Использование Java 10

Наконец, одна из последних версий Java позволяет нам создать неизменяемый список , содержащий элементы данной коллекции:

List<T> copy = List.copyOf(list);

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

8. Заключение

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

Как всегда, образцы кода можно найти на GitHub, здесь и здесь .