1. Обзор
В Java создание копии List иногда может привести к исключению IndexOutOfBoundsException: “Source does not fit in dest”. В этом коротком уроке мы рассмотрим, почему мы получаем эту ошибку при использовании метода Collections.copy | и как ее можно решить. Мы также рассмотрим альтернативы Collections.copy , чтобы сделать копию списка.
2. Воспроизведение проблемы
Давайте начнем с метода создания копии списка с помощью метода Collections.copy :
static ListcopyList(List source) { List destination = new ArrayList<>(source.size()); Collections.copy(destination, source); return destination; }
Здесь метод copy List создает новый список с начальной емкостью , равной размеру исходного списка. Затем он пытается скопировать элементы исходного списка в список назначения:
Listsource = Arrays.asList(1, 2, 3, 4, 5); List copy = copyList(source);
Однако, как только мы вызываем метод copy List , он выдает исключение java.lang.IndexOutOfBoundsException: Source не помещается в dest .
3. Причина исключения
Давайте попробуем понять, что пошло не так. В соответствии с документацией для метода Collections.copy :
Список назначения должен быть по крайней мере таким же длинным, как и список источника. Если он длиннее, то остальные элементы в списке назначения остаются незатронутыми.
В нашем примере мы создали новый List с помощью конструктора с начальной емкостью, равной размеру исходного списка. Он просто выделяет достаточно памяти и на самом деле не определяет элементы. Размер нового списка остается нулевым, поскольку емкость и размер являются различными атрибутами Списка .
Поэтому, когда метод Collections.copy пытается скопировать исходный список в список назначения, он выбрасывает java.lang.IndexOutOfBoundsException.
4. Решения
4.1. Коллекции.копия
Давайте рассмотрим рабочий пример копирования List в другой List , используя метод Collections.copy :
Listdestination = Arrays.asList(1, 2, 3, 4, 5); List source = Arrays.asList(11, 22, 33); Collections.copy(destination, source);
В этом случае мы копируем все три элемента исходного списка в список назначения. Метод Arrays.asList инициализирует список элементами, а не только размером, поэтому мы можем успешно скопировать исходный список в список назначения.
Если мы просто поменяем местами аргументы метода Collections.copy , он выдаст java.lang.IndexOutOfBoundsException потому что размер исходного списка меньше размера списка назначения .
После этой операции копирования список назначения выглядит следующим образом:
[11, 22, 33, 4, 5]
Наряду с методом Collections.copy в Java существуют и другие способы создания копии List . Давайте взглянем на некоторые из них.
4.2. Конструктор ArrayList
Самый простой подход к копированию List – это использование конструктора , который принимает параметр коллекции :
Listsource = Arrays.asList(11, 22, 33); List destination = new ArrayList<>(source);
Здесь мы просто передаем исходный список конструктору списка назначения, который создает неглубокую копию исходного списка.
Список назначения будет просто еще одной ссылкой на тот же объект, на который ссылается список источника. Таким образом, каждое изменение, произведенное любой ссылкой, будет влиять на один и тот же объект.
Поэтому использование конструктора является хорошим вариантом для копирования неизменяемых объектов, таких как Целые числа и Строки.
4.3. addAll
Еще один простой способ-использовать метод addAll списка:
Listdestination = new ArrayList<>(); destination.addAll(source);
Метод addAll скопирует все элементы исходного списка в список назначения.
Есть несколько моментов, которые следует отметить относительно этого подхода:
- Он создает неглубокую копию исходного списка.
- Элементы исходного списка добавляются в список назначения.
4.4. Потоки Java 8
Java 8 представила Stream API , который является отличным инструментом для работы с коллекциями Java .
Используя метод stream () , мы делаем копию списка с помощью Stream API :
Listcopy = source.stream() .collect(Collectors.toList());
4.5. Java 10
Копирование List еще проще в Java 10. Использование метода copyOf() позволяет создать неизменяемый список, содержащий элементы данной коллекции :
Listdestination = List.copyOf(sourceList);
Если мы хотим использовать этот подход, нам нужно убедиться, что входной List не является null и что он не содержит никаких null элементов.
5. Заключение
В этой статье мы рассмотрели, как и почему метод Collections.copy выбрасывает Indexoutofboundsexception “Source does not file in dest” . Наряду с этим мы также исследовали различные способы копирования списка в другой список.
Как примеры pre-Java-10 , так и примеры Java 10 можно найти на GitHub.