Преобразование массива примитивных длин в Список длинных - PullRequest
129 голосов
/ 16 апреля 2009

Это может быть немного простой, головной убор, но моя первая попытка на удивление полностью не сработала. Я хотел взять массив примитивных длин и превратить его в список, который я пытался сделать так:

long[] input = someAPI.getSomeLongs();
List<Long> inputAsList = Arrays.asList(input); //Total failure to even compile!

Как правильно это сделать?

Ответы [ 16 ]

105 голосов
/ 29 декабря 2009

Мне было удобно использовать 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);

РЕДАКТИРОВАТЬ: обновлено, чтобы обеспечить полное преобразование в список, как это предлагается в комментариях и других исправлениях.

99 голосов
/ 16 апреля 2014

Начиная с Java 8, теперь вы можете использовать для этого потоки:

long[] arr = {1,2,3,4};
List<Long> list = Arrays.stream(arr).boxed().collect(Collectors.toList());
37 голосов
/ 02 июня 2010
import java.util.Arrays;
import org.apache.commons.lang.ArrayUtils;

List<Long> longs = Arrays.asList(ArrayUtils.toObject(new long[] {1,2,3,4}));
33 голосов
/ 16 апреля 2009

hallidave и jpalecek имеют правильную идею - итерацию по массиву & mdash; но они не используют преимущества, предоставляемые ArrayList: начиная с размера из списка известен , в этом случае вы должны указать его при создании ArrayList.

List<Long> list = new ArrayList<Long>(input.length);
for (long n : input)
  list.add(n);

Таким образом, ненужные массивы не создаются только для сброса ArrayList, потому что они оказываются слишком короткими, и пустые «слоты» не теряются, потому что ArrayList переоценивает свои требования к пространству. Конечно, если вы продолжите добавлять элементы в список, потребуется новый вспомогательный массив.

17 голосов
/ 05 августа 2015

В качестве другой возможности, библиотека Guava предоставляет это как Longs.asList(), с аналогичными служебными классами для других примитивных типов.

import com.google.common.primitives.Longs;

long[] input = someAPI.getSomeLongs();
List<Long> output = Longs.asList(input);
17 голосов
/ 16 апреля 2009

Немного более многословно, но это работает:

    List<Long> list = new ArrayList<Long>();
    for (long value : input) {
        list.add(value);
    }

В вашем примере кажется, что Arrays.asList () интерпретирует ввод как список длинных массивов [] вместо списка длинных. Немного удивительно, конечно. В этом случае автобокс не работает так, как вы хотите.

7 голосов
/ 16 апреля 2009

Нет, нет автоматического преобразования из массива примитивного типа в массив их ссылочных типов в штучной упаковке. Вы можете сделать только

long[] input = someAPI.getSomeLongs();
List<Long> lst = new ArrayList<Long>();

for(long l : input) lst.add(l);
6 голосов
/ 25 августа 2016

Другой способ с Java 8.

long[] input = someAPI.getSomeLongs();
LongStream.of(input).boxed().collect(Collectors.toList()));
6 голосов
/ 01 февраля 2010

Я пишу небольшую библиотеку для этих проблем:

long[] input = someAPI.getSomeLongs();
List<Long> = $(input).toList();

Если вам не все равно, отметьте здесь .

4 голосов
/ 28 октября 2018

Был задан вопрос о том, как превратить массив в список. Большинство ответов пока показали, как создать новый список с тем же содержимым, что и массив, или ссылаться на сторонние библиотеки. Тем не менее, существуют простые встроенные параметры для такого преобразования. Некоторые из них уже были набросаны в других ответах (например, этот ). Но я хотел бы указать и разработать определенные степени свободы для реализации здесь, и показать потенциальные выгоды, недостатки и предостережения.

Необходимо сделать как минимум два важных различия:

  • Должен ли результирующий список быть представлением в массиве или это должен быть новый список
  • Должен ли результирующий список быть изменяемым или нет

Параметры будут кратко изложены здесь, а полный пример программы показан внизу этого ответа.


Создание нового списка по сравнению с представлением в массиве

Когда результатом должен быть новый список, тогда можно использовать один из подходов из других ответов:

List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());

Но следует учитывать недостатки этого: массив со значениями 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)

Использование view для массива означает, что изменения в массиве будут видны в списке:

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;

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);
        return new AbstractList<Long>()
        {
            @Override
            public Long get(int index)
            {
                return array[index];
            }

            @Override
            public int size()
            {
                return array.length;
            }
        };
    }

    /**
     * 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);
        return new AbstractList<Long>()
        {
            @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;
            }
        };
    }

}

Вывод примера показан здесь:

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
...