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 техник в Sber
7 сентября 2023, 08:43
Почему "способ 1" не работает? Это ошибка в статье или что-то в Java изменилось?
Anton Turin
Уровень 19
6 июня 2023, 09:16
List<String> wordsList = Arrays.asList("I", "love", "learning", "on", "JavaRush");
 String[] wordsArray = wordsList.toArray(new String[0]);
почему ноль в конце? wordlist же не нулевой. или это не про размер массива?
Ulukay
Уровень 19
21 сентября 2023, 17:18
"Какой же метод из трех выбрать? В ранних версиях Java было оптимально передавать массив с длиной равной длине списка или больше нее. Однако в современных JVM есть оптимизации, и в некоторых случаях они обеспечивают более быструю работу метода, в который передается массив меньшей длины, чем длина списка. Так что если вы работаете на современной версии Java, передавайте в метод пустой массив, как мы делали в первом примере:
wordsList.toArray(new String[0]);
" ну а что бы не гадать с длинной (достаточно ли она меньше или еще поменьше указать) можно просто ввести 0 - куда уж меньше.
bighugеmistеr Android Developer
27 ноября 2021, 19:05
Ребят, не получается привести список чисел в массив чисел. Помогите. Чего не хватает?
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[]'
Hidden #213 Урoвень 13 (Forever&Ever)
30 ноября 2021, 09:19
Используй Integer[] 😉
zotov_l88
Уровень 1
28 декабря 2021, 00:30
В intList объекты Integer. Соответственно, нужно создать массив объектов Integer. Должно быть так: Integer[] intArray = (Integer[]) intList.toArray();
bighugеmistеr Android Developer
28 декабря 2021, 02:46
Так пишет: Casting 'intList.toArray()' to 'Integer[]' will produce 'ClassCastException' for any non-null value Программа не запускается.
Сергей
Уровень 51
26 апреля 2022, 14:35
Столкнулся с этой проблемой.
List<String> wordsList = new ArrayList<>();
        list.add("one");
        list.add("two");
	list.add("three");
        String[] wordsArray = (String[]) wordsList.toArray();
Падает с Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String; Однако если сделать как в статье, то все ОК!
List<String> wordsList = Arrays.asList("one", "two", "three");
       String[] wordsArray = (String[]) wordsList.toArray();
В чем разница?? У меня есть только догадки насчет магии кэширования. Но все равно, какого черта?! Решит проблему:
// .....
String[] wordsArray = wordsList.toArray(new String[wordsList.size()]);
И. Ж.
Уровень 41
14 августа 2022, 10:26
Да, последний кусок кода работает, надо явно создать в скобках массив с размером, иначе исключение
Mark
Уровень 19
17 ноября 2021, 19:50
Слов нет насколько полезной для меня оказалась эта статья. Жаль что прочитал ее только сейчас
Ernest Aydinov
Уровень 37
17 марта 2021, 10:29
Я бы добавил в статью одно важное на мой взгляд уточнение. При рассмотрении метода 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;
Barm
Уровень 38
22 декабря 2021, 12:54
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);
        }
    }
}
Да, этот код выбрасывает у меня исключение. Но при этом работает лямбда
String[] wordsArray = wordsList.toArray(String[]::new);
И не понимаю почему. Лямбда использует второй метод toArray?
Ernest Aydinov
Уровень 37
1 февраля 2022, 11:55
я думаю, потому что в вашем примере явно указан тип элементов создаваемого объекта объекта ArrayList
Sherlock0404
Уровень 28
4 марта 2021, 16:51
Отличная статья! спасибо
4 августа 2020, 08:38
List -> List<String>
Pavlo Plynko Java-разработчик в CodeGym Expert
11 августа 2020, 05:09
спасибо!