С потоками, добавленными в Java 8, мы можем написать код типа:
int[] example1 = list.stream().mapToInt(i->i).toArray(); // OR int[] example2 = list.stream().mapToInt(Integer::intValue).toArray();
Мыслительный процесс:
Простой Stream#toArray возвращает Object[] массив, так что это не то, что мы хотим. Кроме того, Stream#toArray(IntFunction<A[]> generator) который возвращает A[], не делает того, что мы хотим, потому что универсальный тип A не может представлять примитивный тип int
Итак, было бы неплохо иметь какой-то поток, который был бы разработан для обработки примитивного типа int вместо ссылочного типа like Integer, потому что его toArray метод, скорее всего, также вернет int[] массив (возвращать что-то другое, например, Object[] или даже в штучной упаковке Integer[] было бы неестественно для int). И, к счастью, в Java 8 есть такой поток, который IntStream
Итак, теперь единственное, что нам нужно выяснить, это как преобразовать наш Stream<Integer> (который будет возвращен из list.stream()) в этот блестящий IntStream.
Быстрый поиск в документации по Stream при поиске методов, которые возвращают IntStream указывает нам на наше решение, которое является mapToInt(ToIntFunction<? super T> mapper) методом. Все, что нам нужно сделать, это предоставить отображение из Integer в int.
Поскольку ToIntFunction это функциональный интерфейс, мы также можем предоставить его экземпляр через lambda или ссылку на метод.
В любом случае, чтобы преобразовать Integer в int, мы можем использовать Integer#intValue so внутри mapToInt мы можем написать:
mapToInt( (Integer i) -> i.intValue() )
(или некоторые могут предпочесть: mapToInt(Integer::intValue).)
Но аналогичный код может быть сгенерирован с помощью распаковки, поскольку компилятор знает, что результат этого лямбда-выражения должен иметь тип int (лямбда, используемая в mapToInt, является реализацией ToIntFunction интерфейса, который ожидает в качестве тела метод типа: int applyAsInt(T value) который, как ожидается, вернет int).
Итак, мы можем просто написать:
mapToInt((Integer i)->i)
Кроме того, поскольку Integer тип в (Integer i) может быть определен компилятором, потому что List<Integer>#stream() возвращает a Stream<Integer>, мы также можем пропустить его, что оставляет нас с
mapToInt(i -> i)
Ответ 2
К сожалению, я не верю, что на самом деле есть лучший способ сделать это из-за особенностей обработки Java примитивных типов, боксов, массивов и обобщений. В частности.:
List<T>.toArray не будет работать, потому что нет преобразования из Integer в int
Вы не можете использовать int в качестве аргумента типа для generics, поэтому это должен быть int специфичный метод (или тот, который использовал отражение для выполнения неприятных трюков).
Я полагаю, что существуют библиотеки, которые имеют автоматически созданные версии такого метода для всех примитивных типов (т. Е. Есть шаблон, который копируется для каждого типа). Это некрасиво, но, боюсь, так оно и есть :(
Несмотря на то, что Arrays класс появился до появления generics в Java, ему все равно пришлось бы включать все ужасные перегрузки, если бы он был представлен сегодня (при условии, что вы хотите использовать примитивные массивы).
List<Integer> list = ... int[] ints = Ints.toArray(list);
Это избавляет вас от необходимости самостоятельно выполнять промежуточное преобразование массива, которое требуется для эквивалента Commons Lang.
Ответ 4
Самый простой способ сделать это - использовать Apache Commons Lang. У него есть удобный класс ArrayUtils, который может делать то, что вы хотите. Используйте toPrimitive метод с перегрузкой для массива Integers.
List<Integer> myList; ... assign and fill the list int[] intArray = ArrayUtils.toPrimitive(myList.toArray(newInteger[myList.size()]));
Таким образом, вы не изобретаете велосипед заново. В Commons Lang есть множество полезных вещей, которые Java упустила. Выше я решил создать список целых чисел нужного размера. Вы также можете использовать статический целочисленный массив длиной 0 и позволить Java выделить массив нужного размера: