JavaRush /Java блог /Java Developer /Java list to array: преобразуем список элементов в массив...
Анзор Кармов
31 уровень
Санкт-Петербург

Java list to array: преобразуем список элементов в массив

Статья из группы Java Developer
Привет! В данной статье мы рассмотрим, как в Java преобразовать список элементов в массив элементов. Собственно, способов сделать это не так уж и много, и все они простые, так что статья будет несложной. Java list to array: преобразуем список элементов в массив - 1Сразу же определимся, с чем мы работаем. Будем конвертировать списки в массивы, а конкретнее — список строк: I, love, learning, on, JavaRush будем преобразовывать в массив таких же строк. Но для начала маленький бонус. Расскажем о том, как по быстрому запилить списочек.

Как по быстрому запилить списочек list to array

Запомни: в этой жизни есть два сценария. Первый — полнейшая тоска и скука, когда мы инициализируем новый список:

List<String> wordsList = new ArrayList();
А потом добавляем в него значения... По одному…

wordsList.add("I");
wordsList.add("love");
wordsList.add("learning");
wordsList.add("on");
wordsList.add("JavaRush");
Никуда не годится. Уже забыл, зачем нужен был список, пока его создавал! Второй путь — отсечение всего лишнего и принятие... классов утилит. Например, класса Arrays, в котором есть невероятно удобный метод asList. В него можно передавать все, что ты хочешь сделать списком, и метод сделает это списком. Вот примерно так:

List<String> wordsList = Arrays.asList("I", "love", "learning", "on", "JavaRush");
Данный метод принимает в себя varargs — в некотором смысле массив. Прошу прощения за то, что в лекции под названием list to array я научил тебя сначала array to list, но того требовали обстоятельства. Ну а теперь к нашим методам перевода списков в массивы.

Способ №1. Перебор

Способ отлично подойдет тем, кто любит не особо вдумчиво набирать код на клавиатуре. Своего рода медитация. Шаг 1. Создаем массив такой же длины, как и список:

List<String> wordsList = Arrays.asList("I", "love", "learning", "on", "JavaRush");
String[] wordsArray = new String[wordsList.size()];
Шаг 2. Создаем цикл со счетчиком, чтобы пробежаться по всем элементам списка и иметь возможность обращаться к ячейкам массива по индексу:

for (int i = 0; i < wordsList.size(); i++) {

}
Шаг 3. Внутри цикла значение каждого элемента списка с индексом i присваиваем ячейке массива с индексом i:

for (int i = 0; i < wordsList.size(); i++) {
    wordsArray[i] = wordsList.get(i);
}
Итог:

public static void main(String[] args) {

        List<String> wordsList = Arrays.asList("I", "love", "learning", "on", "JavaRush");
        String[] wordsArray = new String[wordsList.size()];

        for (int i = 0; i < wordsList.size(); i++) {
            wordsArray[i] = wordsList.get(i);
        }
    }

Способ №2. Метод toArray

Наверное, самая оптимальная в использовании штуковина. В интерфейсе List есть два метода toArray, которые из текущего списка создают массив:

Object[] toArray();
 T[] toArray(T[] a);
Первый метод возвращает массив объектов, в котором расположены все элементы текущего списка (от первого до последнего):

public class Main {
    public static void main(String[] args) {
        List<String> wordsList = Arrays.asList("I", "love", "learning", "on", "JavaRush");
        String[] wordsArray = (String[]) wordsList.toArray();

        for (String word : wordsArray) {
            System.out.println(word);
        }

    }
}

Запустим метод main и увидим следующее:

I
love
learning
on
JavaRush
Однако у данного метода есть особенность: он всегда возвращает массив объектов (Object[]). Поэтому возвращаемый результат необходимо привести к нужному типу данных. В примере выше мы привели его к массиву строк (String[]). Зато данный метод не принимает аргументов, что в некоторых ситуациях может быть удобно. Второй метод также возвращает массив, в котором расположены все элементы текущего списка (от первого до последнего). Однако в отличие от первого, второй метод принимает в качестве аргумента массив определенного типа. Но и результатом работы второго метода будет не массив объектов, а массив определенного типа данных — такого же, как и тип данных в переданном в аргументы методе массива.

public class Main {
    public static void main(String[] args) {
        List<String> wordsList = Arrays.asList("I", "love", "learning", "on", "JavaRush");
        String[] wordsArray = wordsList.toArray(new String[0]); 

        for (String word : wordsArray) {
            System.out.println(word);
        }

    }
}
Если запустить метод main, в выводе мы увидим все те же слова:

I
love
learning
on
JavaRush
Поговорим немного о массиве, который передается в качестве аргумента методу toArray. Логика работы метода зависит от длины передаваемого массива. Есть три возможные сценария:

1. Длина передаваемого массива меньше, чем длина списка

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

2. Длина передаваемого элемента равна длине списка

Метод поместит элементы списка в переданный массив. Продемонстрируем это:

public class Main {
    public static void main(String[] args) {
        List<String> wordsList = Arrays.asList("I", "love", "learning", "on", "JavaRush");
        
        // Создаем пустой массив нужной длины
        String[] array = new String[wordsList.size()];

        // Отправляем пустой массив в метод toArray
        wordsList.toArray(array);

        // Проверяем, заполнился ли наш массив. Спойлер: да
        for (String word : array) {
            System.out.println(word);
        }

    }
}
При выводе мы увидим все те же строки, и станет ясно, что метод заполнил созданный нами массив.

3. Длина передаваемого массива больше, чем длина списка

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

public class Main {
    public static void main(String[] args) {
        List<String> wordsList = Arrays.asList("I", "love", "learning", "on", "JavaRush");

        // Создаем пустой массив, длина которого в 2 раза больше длины списка
        String[] array = new String[wordsList.size() * 2];

        for (int i = 0; i < array.length; i++) {
            // В каждую ячейку запишем строковое представление текущего индекса
            array[i] = String.valueOf(i);
        }

        // Отправляем массив в метод toArray
        wordsList.toArray(array);

        // Проверяем, что лежит в нашем массиве
        for (String word : array) {
            System.out.println(word);
        }

    }
}
После запуска метода main в консоли увидим следующее:

I
love
learning
on
JavaRush
null
6
7
8
9
Какой же метод из трех выбрать? В ранних версиях Java было оптимально передавать массив с длиной равной длине списка или больше нее. Однако в современных JVM есть оптимизации, и в некоторых случаях они обеспечивают более быструю работу метода, в который передается массив меньшей длины, чем длина списка. Так что если вы работаете на современной версии Java, передавайте в метод пустой массив, как мы делали в первом примере:

wordsList.toArray(new String[0]);

Способ №3. Stream API

Данный способ подойдет тем, кто хочет не просто перевести список в массив, но и попутно решить пару тройку других задач. А еще — людям, знакомым с Java Stream API. На JavaRush есть неплохая статья на эту тему. В данном разделе мы разберем несколько примеров с использованием стримов. Как с помощью стримов привести список к массиву:

public class Main {
    public static void main(String[] args) {
        List<String> wordsList = Arrays.asList("I", "love", "learning", "on", "JavaRush");

        String[] strings = wordsList.stream()
                .toArray(String[]::new);

        for (String s : strings) {
            System.out.println(s);
        }

        /*
        Output:
        I
        love
        learning
        on
        JavaRush

         */
    }
}
Но если вам просто нужно привести список к массиву, то лучше сделать это с помощью метода toArray, описанном в разделе Способ №2. А вот если вы хотите не просто привести список к массиву, а еще и произвести некоторое действие над каждым элементом, тогда вам по адресу. Попробуем привести список к массиву так, чтобы в итоговом массиве все строки были записаны в верхнем регистре:

public class Main {
    public static void main(String[] args) {
        List<String> wordsList = Arrays.asList("I", "love", "learning", "on", "JavaRush");

        String[] strings = wordsList.stream()
                .map(str -> str.toUpperCase())
                .toArray(String[]::new);

        for (String s : strings) {
            System.out.println(s);
        }

        /*
            Output:
            I
            LOVE
            LEARNING
            ON
            JAVARUSH

         */
    }
}

Здесь, в .map(str -> str.toUpperCase()) мы определили, что нужно сделать с каждой строкой в списке. В данном случае мы решили преобразовывать каждую строку в верхний регистр, а затем собирать ее в массив. Использование Stream API позволяет не только преобразовывать каждое значение, но и фильтровать их. Предположим, мы хотим из списка строк собрать массив, но таким образом, чтобы в массив попали только строки длиной более двух символов:

public class Main {
    public static void main(String[] args) {
        List<String> wordsList = Arrays.asList("I", "love", "learning", "on", "JavaRush");

        String[] strings = wordsList.stream()
                .filter(str -> str.length() > 2)
                .map(str -> str.toUpperCase())
                .toArray(String[]::new);

        for (String s : strings) {
            System.out.println(s);
        }

        /*
            Output:
            LOVE
            LEARNING
            JAVARUSH
         */
    }
}
Здесь в строке .filter(str -> str.length() > 2) мы создали так называемый фильтр, который будет применяться к каждому элементу списка, прежде чем он попадет в массив. В данном случае у каждой строки вызывается метод length(), и если результат выражения str.length() > 2 истинный, такая строка попадет в результирующую выборку, а в итоге в массив. Иначе — не попадет. Здесь, пожалуй, стоит сказать, что того же можно добиться, просто перебирая элементы и накладывая различные ограничения. Можно делать и так. Stream API предоставляет более функциональный подход для решения подобных задач.

Итоги

В данной статье мы рассмотрели различные способы приведения списков к массивам:
  • простой перебор;
  • метод toArray;
  • Stream API.
Самый оптимальный вариант — использовать метод toArray, который определен в интерфейсе List. Таких методов два:
  • Object[] toArray();
  • T[] toArray(T[] a);
Первый не принимает аргументы, но возвращает массив объектов, из-за чего чаще всего придется прибегать к явному приведению типов. Второй возвращает массив нужного типа, но в качестве аргумента принимает массив. Лучше всего передавать пустой массив в метод, и будет вам счастье. Использование Stream API позволяет не только привести список к массиву, но и попутно провести некоторые действия, например отфильтровать или преобразовать элементы, перед добавлением их в массив.

Домашка

Попробуйте повторить все примеры из данной статьи самостоятельно, только вместо исходного списка строк используйте список целых чисел от 0 до 10. Естественно, некоторые условия из примеров, применимые только для строк, вам придется адаптировать под новые условия.
Комментарии (16)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
ChupaFx Уровень 32
7 сентября 2023
Почему "способ 1" не работает? Это ошибка в статье или что-то в Java изменилось?
Anton Turin Уровень 19
6 июня 2023

List<String> wordsList = Arrays.asList("I", "love", "learning", "on", "JavaRush");
 String[] wordsArray = wordsList.toArray(new String[0]);
почему ноль в конце? wordlist же не нулевой. или это не про размер массива?
bighugеmistеr Уровень 15
27 ноября 2021
Ребят, не получается привести список чисел в массив чисел. Помогите. Чего не хватает?

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Test {
    public static void main(String[] args) {
        List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        int[] intArray = (int[]) intList.toArray();
    }
}
Возникает ошибка: Inconvertible types; cannot cast 'java.lang.Object[]' to 'int[]'
Mark Уровень 19
17 ноября 2021
Слов нет насколько полезной для меня оказалась эта статья. Жаль что прочитал ее только сейчас
Ernest Aydinov Уровень 37
17 марта 2021
Я бы добавил в статью одно важное на мой взгляд уточнение. При рассмотрении метода Object[] toArray() в Способе №2, в примере при создании ArrayList(), вы использовали Arrays.asList Однако Arrays.asList() вернет объект класса ArrayList который является внутренним приватным статическим классом (private static class ArrayList<E> extends AbstractList<E>) класса Arrays, а это не класс java.util.ArrayList. Большинство же использует именно класс java.util.ArrayList и при попытке приведения типа массива Object[] к String[] в строке:

String[] wordsArray = (String[]) wordsList.toArray();
выкинет исключение: Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
Sherlock0404 Уровень 28
4 марта 2021
Отличная статья! спасибо
4 августа 2020
List -> List<String>