1. Общ преглед
В Java, копирането на списък понякога може да доведе до IndexOutOfBoundsException: „Източникът не се побира в дестинация“. В този кратък урок ще разгледаме защо получаваме тази грешка при използване на метода Collections.copy и как тя може да бъде решена. Ще разгледаме и алтернативи на Collections.copy, за да направим копие на списъка.
2. Възпроизвеждане на проблема
Нека започнем с метод за създаване на копие на Списък, използвайки метода Collections.copy :
static List copyList(List source) { List destination = new ArrayList(source.size()); Collections.copy(destination, source); return destination; }
Тук методът copyList създава нов списък с първоначален капацитет, равен на размера на списъка източник. След това се опитва да копира елементите от списъка с източници в списъка с местоназначения:
List source = Arrays.asList(1, 2, 3, 4, 5); List copy = copyList(source);
След като обаче извикаме метода copyList , той хвърля изключение java.lang.IndexOutOfBoundsException: Източникът не се побира в dest .
3. Причина за изключението
Нека се опитаме да разберем какво се обърка. Според документацията за метода Collections.copy :
Целевият списък трябва да бъде поне толкова дълъг, колкото списъка източник. Ако е по-дълго, останалите елементи в списъка с дестинации не се влияят.
В нашия пример създадохме нов Списък, използвайки конструктор с първоначален капацитет, равен на размера на списъка източник. Той просто разпределя достатъчно памет и всъщност не дефинира елементи. Размерът на новия списък остава нула, тъй като капацитетът и размерът са различни атрибути на списъка .
Следователно, когато методът Collections.copy се опитва да копира списъка с източници в целевия списък, той хвърля java.lang.IndexOutOfBoundsException.
4. Решения
4.1. Колекции.копия
Нека да разгледаме работещ пример за копиране на списък в друг списък , използвайки метода Collections.copy :
List destination = 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
Най-простият подход за копиране на Списък е използването на конструктор, който приема параметър Collection :
List source = Arrays.asList(11, 22, 33); List destination = new ArrayList(source);
Тук просто предаваме списъка с източници на конструктора на списъка с дестинации, който създава плитко копие на списъка с източници.
Списъкът на дестинациите ще бъде просто още една препратка към същия обект, посочен от списъка източник. Така че всяка промяна, направена от която и да е препратка, ще засегне един и същ обект.
Следователно използването на конструктор е добра опция за копиране на неизменяеми обекти като цели числа и низове.
4.3. добави Всички
Друг прост начин е да се използва методът addAll от Списък :
List destination = new ArrayList(); destination.addAll(source);
Методът addAll ще копира всички елементи от списъка с източници в списъка с местоназначения.
Има няколко точки, които трябва да се отбележат по отношение на този подход:
- Създава плитко копие на списъка с източници.
- Елементите на списъка с източници се добавят към списъка с дестинации.
4.4. Java 8 потоци
Java 8 представи Stream API, който е чудесен инструмент за работа с Java Collections.
Използвайки метода stream () , правим копие на списъка, използвайки Stream API :
List copy = source.stream() .collect(Collectors.toList());
4.5. Java 10
Копирането на списък е още по-просто в Java 10. Използването на метода copyOf () ни позволява да създадем неизменим списък, съдържащ елементите на дадената колекция :
List destination = List.copyOf(sourceList);
Ако искаме да използваме този подход, трябва да се уверим, че входният списък не е нулев и че не съдържа никакви нулеви елементи.
5. Заключение
В тази статия разгледахме как и защо методът Collections.copy хвърля IndexOutOfBoundException „Източникът не се записва в dest“ . Заедно с него проучихме и различни начини за копиране на списък в друг списък.
Както примерите преди Java-10, така и примерите за Java 10 могат да бъдат намерени в GitHub.