Преобразование массива в List и обратно - Вопросы
Всего: 6 вопросов
1. Почему Arrays.asList(intArray) возвращает список из одного элемента?
Почему Arrays.asList(intArray) возвращает список из одного элемента?
Метод объявлен как Arrays.asList(T... a), а параметр типа T может быть только ссылочным типом. Массив int[] сам является объектом, поэтому компилятор передаёт его как один varargs-аргумент и выводит тип результата List<int[]> размером 1, а не List<Integer> из трёх элементов.
int[] numbers = {1, 2, 3};
// Неправильно: список из ОДНОГО элемента — самого массива
List<int[]> wrong = Arrays.asList(numbers);
System.out.println(wrong.size()); // 1
// Правильно: сначала распаковываем поток
List<Integer> right = Arrays.stream(numbers).boxed().toList();
System.out.println(right.size()); // 3
Для массива объектов (Integer[], String[]) Arrays.asList() действительно даёт список из всех элементов, но этот список имеет фиксированный размер: add() и remove() бросят UnsupportedOperationException.
2. Как преобразовать массив int[] в List<Integer> и чем Stream.toList() отличается от collect(Collectors.toList())?
Как преобразовать массив int[] в List<Integer> и чем Stream.toList() отличается от collect(Collectors.toList())?
Преобразование делается в три шага: Arrays.stream() создаёт IntStream, boxed() упаковывает каждый int в Integer, а терминальная операция собирает результат в список.
int[] numbers = {1, 2, 3, 4, 5};
// Изменяемый список
List<Integer> list = Arrays.stream(numbers)
.boxed()
.collect(Collectors.toList());
// Java 16+: короче, но список неизменяемый
List<Integer> immutable = Arrays.stream(numbers).boxed().toList();
Stream.toList() появился в Java 16 и всегда возвращает неизменяемый список (допускающий null): add() или set() выбросят UnsupportedOperationException. Коллектор Collectors.toList() возвращает изменяемый список, на практике ArrayList, но конкретная реализация спецификацией не гарантируется.
3. Как преобразовать List<Integer> обратно в массив int[] и чем это опасно при наличии null?
Как преобразовать List<Integer> обратно в массив int[] и чем это опасно при наличии null?
Обратное преобразование зеркально прямому: mapToInt() распаковывает каждый Integer в int, а toArray() собирает примитивный массив.
List<Integer> list = List.of(10, 20, 30, 40);
int[] array = list.stream()
.mapToInt(Integer::intValue)
.toArray();
System.out.println(Arrays.toString(array)); // [10, 20, 30, 40]
Тот же код работает и для ArrayList<Integer>, потому что ArrayList — это List. Вариант list.toArray(new int[0]) не компилируется: toArray() работает только с массивами объектов. Если в списке может оказаться null, распаковка упадёт с NullPointerException — отфильтруйте значения заранее через .filter(Objects::nonNull).
4. Чем различаются int[], Integer[] и List<Integer> и как преобразовать их друг в друга?
Чем различаются int[], Integer[] и List<Integer> и как преобразовать их друг в друга?
int[] — массив примитивов, Integer[] — массив объектов-обёрток, List<Integer> — коллекция этих обёрток. Это три несовместимых типа: присваивание int[] a = integerArray; не компилируется, каждая пара требует явного преобразования.
// int[] -> Integer[]
int[] primitives = {1, 2, 3};
Integer[] boxed = Arrays.stream(primitives)
.boxed()
.toArray(Integer[]::new);
// Integer[] -> int[]
Integer[] source = {4, 5, 6};
int[] unboxed = Arrays.stream(source)
.mapToInt(Integer::intValue)
.toArray();
// Integer[] -> изменяемый List<Integer>
List<Integer> list = new ArrayList<>(Arrays.asList(source));
// List<Integer> -> Integer[]
Integer[] back = list.toArray(new Integer[0]);
Обратите внимание: Arrays.asList(source) для Integer[] действительно даёт список из трёх элементов, потому что это массив объектов. С int[] тот же код ведёт себя иначе.
5. Как преобразовать массив int[] именно в ArrayList<Integer>, а не просто в List?
Как преобразовать массив int[] именно в ArrayList<Integer>, а не просто в List?
List — это интерфейс, и конкретная реализация за ним спецификацией не гарантируется. Если по сигнатуре метода нужен именно ArrayList<Integer>, попросите его явно — через коллектор Collectors.toCollection(ArrayList::new) или обернув готовый список.
int[] numbers = {1, 2, 3, 4, 5};
// Вариант 1: собрать сразу в ArrayList
ArrayList<Integer> arrayList = Arrays.stream(numbers)
.boxed()
.collect(Collectors.toCollection(ArrayList::new));
// Вариант 2: обернуть готовый список
ArrayList<Integer> copy = new ArrayList<>(list);
arrayList.add(6); // работает, размер не фиксирован
Оба варианта дают полноценный изменяемый ArrayList, в который можно добавлять и из которого можно удалять элементы — в отличие от результата Stream.toList() и от списка из Arrays.asList().
6. Как преобразовать массив не в List, а в другую коллекцию — например в Set<Integer> или LinkedList<Integer>?
Как преобразовать массив не в List, а в другую коллекцию — например в Set<Integer> или LinkedList<Integer>?
В приёме нет ничего специфичного для List: меняется только коллектор. Связка Arrays.stream(arr).boxed() остаётся прежней, а Collectors.toSet() или Collectors.toCollection(...) задают нужную реализацию Collection.
int[] numbers = {3, 1, 2, 3};
// int[] -> Set<Integer> (дубликаты отбрасываются)
Set<Integer> set = Arrays.stream(numbers).boxed().collect(Collectors.toSet());
// int[] -> LinkedList<Integer>
LinkedList<Integer> linked = Arrays.stream(numbers)
.boxed()
.collect(Collectors.toCollection(LinkedList::new));
// любая Collection<Integer> -> int[]
int[] fromSet = set.stream().mapToInt(Integer::intValue).toArray();
Обратное преобразование одинаково для всех коллекций: stream().mapToInt(Integer::intValue).toArray(). А для массива объектов шаг упаковки не нужен вовсе: List<String> words = new ArrayList<>(Arrays.asList(stringArray));.