Это может быть довольно простой вопрос для руководителя службы, но моя первая попытка на удивление полностью не сработала. Я хотел взять массив примитивных длинных значений и превратить его в список, что я попытался сделать вот так:
long[] input = someAPI.getSomeLongs();
List<Long> inputAsList = Arrays.asList(input); //Total failure to even compile!
Как правильно это сделать?
java
arrays
collections
boxing
Брэндон Ярбро
источник
источник
Ответы:
Мне было удобно использовать apache commons lang ArrayUtils ( JavaDoc , зависимость от Maven )
import org.apache.commons.lang3.ArrayUtils; ... long[] input = someAPI.getSomeLongs(); Long[] inputBoxed = ArrayUtils.toObject(input); List<Long> inputAsList = Arrays.asList(inputBoxed);
у него также есть обратный API
long[] backToPrimitive = ArrayUtils.toPrimitive(objectArray);
РЕДАКТИРОВАТЬ: обновлено, чтобы обеспечить полное преобразование в список в соответствии с комментариями и другими исправлениями.
источник
Arrays.asList(ArrayUtils.toObject(input))
наверное, легко могут это сделать .List<Long> = Arrays.asList(inputBoxed)
в их вопрос, я счел излишним повторять его, поскольку я думал, что это было очевидно, я думаю, я был неправ ...Начиная с Java 8, теперь вы можете использовать для этого потоки:
long[] arr = {1,2,3,4}; List<Long> list = Arrays.stream(arr).boxed().collect(Collectors.toList());
источник
stream
функция определена только дляint[]
,long[]
иdouble[]
.LongStream.of(arr).boxed()...
.Arrays.stream(arr).boxed().collect(Collectors.toList());
К сожалению, это может только вернутьсяList<Object>
import java.util.Arrays; import org.apache.commons.lang.ArrayUtils; List<Long> longs = Arrays.asList(ArrayUtils.toObject(new long[] {1,2,3,4}));
источник
Hallidave и jpalecek имеют правильную идею - итерацию по массиву, - но они не используют преимущества, предоставляемые
ArrayList
: поскольку размер списка известен в этом случае, вы должны указать его при созданииArrayList
.List<Long> list = new ArrayList<Long>(input.length); for (long n : input) list.add(n);
Таким образом, не создаются ненужные массивы, которые могут быть отброшены,
ArrayList
потому что они оказываются слишком короткими, и пустые «слоты» не тратятся впустую из-заArrayList
завышенных требований к пространству. Конечно, если вы продолжите добавлять элементы в список, потребуется новый резервный массив.источник
Немного более подробный, но это работает:
List<Long> list = new ArrayList<Long>(); for (long value : input) { list.add(value); }
В вашем примере кажется, что Arrays.asList () интерпретирует ввод как список массивов long [] вместо списка Long. Это, конечно, немного удивительно. В данном случае автобоксинг работает не так, как вы хотите.
источник
В качестве другой возможности библиотека Guava предоставляет это as
Longs.asList()
с аналогичными служебными классами для других примитивных типов.import com.google.common.primitives.Longs; long[] input = someAPI.getSomeLongs(); List<Long> output = Longs.asList(input);
источник
Нет, автоматического преобразования из массива примитивного типа в массив их ссылочных типов в штучной упаковке нет. Ты можешь только делать
long[] input = someAPI.getSomeLongs(); List<Long> lst = new ArrayList<Long>(); for(long l : input) lst.add(l);
источник
Задан вопрос о том, как превратить массив в список. Большинство ответов до сих пор показывали, как создать новый список с тем же содержимым, что и массив, или со ссылкой на сторонние библиотеки. Однако для такого преобразования есть простые встроенные опции. Некоторые из них уже были обрисованы в других ответах (например, в этом ). Но я хотел бы указать и подробно описать определенные степени свободы для реализации здесь, а также показать потенциальные преимущества, недостатки и предостережения.
Следует сделать как минимум два важных различия:
Здесь будут кратко описаны варианты, а полный пример программы показан внизу этого ответа.
Создание нового списка по сравнению с созданием представления в массиве
Когда результатом должен быть новый список, можно использовать один из подходов из других ответов:
Но следует учитывать недостатки этого: массив из 1000000
long
значений будет занимать примерно 8 мегабайт памяти. Новый список также займет примерно 8 мегабайт. И, конечно же, при создании этого списка необходимо пройти по всему массиву. Во многих случаях создание нового списка просто не требуется. Вместо этого достаточно создать представление массива:// This occupies ca. 8 MB long array[] = { /* 1 million elements */ } // Properly implemented, this list will only occupy a few bytes, // and the array does NOT have to be traversed, meaning that this // operation has nearly ZERO memory- and processing overhead: List<Long> list = asList(array);
(См. Пример внизу для реализации
toList
метода)Следствием наличия представления на массиве является то, что изменения в массиве будут видны в списке:
long array[] = { 12, 34, 56, 78 }; List<Long> list = asList(array); System.out.println(list.get(1)); // This will print 34 // Modify the array contents: array[1] = 12345; System.out.println(list.get(1)); // This will now print 12345!
К счастью, создание копии (то есть нового списка, на который не влияют изменения в массиве) из представления тривиально:
List<Long> copy = new ArrayList<Long>(asList(array));
Это настоящая копия, эквивалентная тому, что было достигнуто с помощью потокового решения, которое было показано выше.
Создание изменяемого представления или неизменяемого представления
Во многих случаях достаточно, чтобы список был доступен только для чтения . Содержимое результирующего списка часто не будет изменено, а будет передано только последующей обработке, которая только читает список.
Разрешение на внесение изменений в список вызывает ряд вопросов:
long array[] = { 12, 34, 56, 78 }; List<Long> list = asList(array); list.set(2, 34567); // Should this be possible? System.out.println(array[2]); // Should this print 34567? list.set(3, null); // What should happen here? list.add(99999); // Should this be possible?
Можно создать вид списка для изменяемого массива . Это означает, что изменения в списке, например установка нового значения по определенному индексу, будут видны в массиве.
Но невозможно создать структурно изменяемое представление списка . Это означает, что невозможно выполнять операции, влияющие на размер списка. Это просто потому, что размер базового массива нельзя изменить.
Ниже приводится MCVE, демонстрирующий различные варианты реализации и возможные способы использования полученных списков:
import java.util.AbstractList; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.RandomAccess; public class PrimitiveArraysAsLists { public static void main(String[] args) { long array[] = { 12, 34, 56, 78 }; // Create VIEWS on the given array List<Long> list = asList(array); List<Long> unmodifiableList = asUnmodifiableList(array); // If a NEW list is desired (and not a VIEW on the array), this // can be created as well: List<Long> copy = new ArrayList<Long>(asList(array)); System.out.println("array : " + Arrays.toString(array)); System.out.println("list : " + list); System.out.println("unmodifiableList: " + unmodifiableList); System.out.println("copy : " + copy); // Modify a value in the array. The changes will be visible // in the list and the unmodifiable list, but not in // the copy. System.out.println("Changing value at index 1 of the array..."); array[1] = 34567; System.out.println("array : " + Arrays.toString(array)); System.out.println("list : " + list); System.out.println("unmodifiableList: " + unmodifiableList); System.out.println("copy : " + copy); // Modify a value of the list. The changes will be visible // in the array and the unmodifiable list, but not in // the copy. System.out.println("Changing value at index 2 of the list..."); list.set(2, 56789L); System.out.println("array : " + Arrays.toString(array)); System.out.println("list : " + list); System.out.println("unmodifiableList: " + unmodifiableList); System.out.println("copy : " + copy); // Certain operations are not supported: try { // Throws an UnsupportedOperationException: This list is // unmodifiable, because the "set" method is not implemented unmodifiableList.set(2, 23456L); } catch (UnsupportedOperationException e) { System.out.println("Expected: " + e); } try { // Throws an UnsupportedOperationException: The size of the // backing array cannot be changed list.add(90L); } catch (UnsupportedOperationException e) { System.out.println("Expected: " + e); } try { // Throws a NullPointerException: The value 'null' cannot be // converted to a primitive 'long' value for the underlying array list.set(2, null); } catch (NullPointerException e) { System.out.println("Expected: " + e); } } /** * Returns an unmodifiable view on the given array, as a list. * Changes in the given array will be visible in the returned * list. * * @param array The array * @return The list view */ private static List<Long> asUnmodifiableList(long array[]) { Objects.requireNonNull(array); class ResultList extends AbstractList<Long> implements RandomAccess { @Override public Long get(int index) { return array[index]; } @Override public int size() { return array.length; } }; return new ResultList(); } /** * Returns a view on the given array, as a list. Changes in the given * array will be visible in the returned list, and vice versa. The * list does not allow for <i>structural modifications</i>, meaning * that it is not possible to change the size of the list. * * @param array The array * @return The list view */ private static List<Long> asList(long array[]) { Objects.requireNonNull(array); class ResultList extends AbstractList<Long> implements RandomAccess { @Override public Long get(int index) { return array[index]; } @Override public Long set(int index, Long element) { long old = array[index]; array[index] = element; return old; } @Override public int size() { return array.length; } }; return new ResultList(); } }
Результат примера показан здесь:
array : [12, 34, 56, 78] list : [12, 34, 56, 78] unmodifiableList: [12, 34, 56, 78] copy : [12, 34, 56, 78] Changing value at index 1 of the array... array : [12, 34567, 56, 78] list : [12, 34567, 56, 78] unmodifiableList: [12, 34567, 56, 78] copy : [12, 34, 56, 78] Changing value at index 2 of the list... array : [12, 34567, 56789, 78] list : [12, 34567, 56789, 78] unmodifiableList: [12, 34567, 56789, 78] copy : [12, 34, 56, 78] Expected: java.lang.UnsupportedOperationException Expected: java.lang.UnsupportedOperationException Expected: java.lang.NullPointerException
источник
Другой способ с Java 8.
long[] input = someAPI.getSomeLongs(); LongStream.of(input).boxed().collect(Collectors.toList()));
источник
Я пишу небольшую библиотеку для этих задач:
long[] input = someAPI.getSomeLongs(); List<Long> = $(input).toList();
Если вам интересно, проверьте это здесь .
источник
Другой способ с Java 8.
final long[] a = new long[]{1L, 2L}; final List<Long> l = Arrays.stream(a).boxed().collect(Collectors.toList());
источник
Arrays.stream(a).boxed().collect(Collectors.<Long>toList());
Объединяя ответы Павла и Тома, мы получаем следующее
@SuppressWarnings("unchecked") public static <T> List<T> asList(final Object array) { if (!array.getClass().isArray()) throw new IllegalArgumentException("Not an array"); return new AbstractList<T>() { @Override public T get(int index) { return (T) Array.get(array, index); } @Override public int size() { return Array.getLength(array); } }; }
источник
Если вам нужна аналогичная семантика,
Arrays.asList
вам нужно будет написать (или использовать чью-то еще) клиентскую реализациюList
(возможно, черезAbstractList
. Она должна иметь почти такую же реализацию, какArrays.asList
только значения box и unbox.источник
Вы можете использовать трансморф :
Transmorph transmorph = new Transmorph(new DefaultConverters()); List<Long> = transmorph.convert(new long[] {1,2,3,4}, new TypeReference<List<Long>>() {});
Это также работает, например, если источник - это массив целых чисел.
источник
Я знаю, что этот вопрос достаточно старый, но ... вы также можете написать свой собственный метод преобразования:
@SuppressWarnings("unchecked") public static <T> List<T> toList(Object... items) { List<T> list = new ArrayList<T>(); if (items.length == 1 && items[0].getClass().isArray()) { int length = Array.getLength(items[0]); for (int i = 0; i < length; i++) { Object element = Array.get(items[0], i); T item = (T)element; list.add(item); } } else { for (Object i : items) { T item = (T)i; list.add(item); } } return list; }
После включения с помощью статического импорта возможны следующие варианты использования:
long[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; List<Long> list = toList(array);
или
List<Long> list = toList(1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l);
источник
catch (ArrayIndexOutOfBoundsException ex) { /* Finished getting array elements */ }
ты ужасный человек.Хотя можно создать новый список и добавить в него все значения (с помощью цикла for или потоков), я работал с действительно большими массивами и получаю низкую производительность. Поэтому я создал свой собственный простой в использовании класс-оболочку примитивного массива.
Пример:
long[] arr = new long[] {1,2,3}; PrimativeList<Long> list = PrimativeList.create(arr); // detects long[] and returns PrimativeList<Long> System.out.println(list.get(1)); // prints: 2 list.set(2, 15); System.out.println(arr[2]); // prints: 15
Получите это здесь: https://github.com/Sf298/Sauds-Toolbox/blob/master/src/main/java/PrimitiveArrayWrapper/PrimitiveList.java
ПРИМЕЧАНИЕ. Я еще не тестировал его полностью, поэтому дайте мне знать, если вы обнаружите какие-либо ошибки / проблемы.
источник
Вы можете использовать
LongStream
для этогоList<Long> longs = LongStream.of(new long[]{1L, 2L, 3L}).boxed() .collect(Collectors.toList());
источник