将原始long数组转换为long列表


138

这可能是一个简单的,总机问题,但我的第一次尝试出乎意料地完全失败了。我想获取一组原始的long并将其转换为列表,我试图这样做:

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

什么是正确的方法?


6
我认为我们对整数有相同的疑问,不是吗?
Tom Hawtin-大头钉

Answers:


115

我发现使用apache commons lang ArrayUtils(JavaDocMaven依赖项)很方便

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);

编辑:更新以提供完整的转换为列表,如注释和其他修复建议。


3
考虑到这会创建一个Longs 数组而不是一个List 数组,所以它无法回答OP的问题并引起我的反对。这到底是怎么得到56次投票和令人垂涎的“检查”的????
user949300 2014年

7
因为人们很容易就能做到Arrays.asList(ArrayUtils.toObject(input))
伊兰·棉兰2014年

我同意@ user949300。这不能回答问题。
dev4life 2015年

1
应该更新此答案以提供对列表的完整转换。但是,这是迈向解决方案的有效步骤。
吉姆·杰弗斯

2
@JimJeffers-谢谢,已更新为包含完整的转换。由于OP包含List<Long> = Arrays.asList(inputBoxed)在他们的问题中,所以我发现重复重复它很困难,因为我认为这很明显,我想我错了……
Eran Medan

114

从Java 8开始,您现在可以使用流:

long[] arr = {1,2,3,4};
List<Long> list = Arrays.stream(arr).boxed().collect(Collectors.toList());

7
好一个!不幸的是,和有些神秘,该stream功能只用于定义int[]long[]double[]
2014年

1
或者,您可以使用LongStream.of(arr).boxed()...
aioobe

2
Arrays.stream(arr).boxed().collect(Collectors.toList());不幸的是,这只能返回List<Object>
Senthilkumar Annadurai

没有笨重的库来完成简单的任务,没有循环。好答案。
亚历克斯奎利亚姆

37
import java.util.Arrays;
import org.apache.commons.lang.ArrayUtils;

List<Long> longs = Arrays.asList(ArrayUtils.toObject(new long[] {1,2,3,4}));

5
对此进行解释以及这是否是第三方库将很有帮助。
IgorGanapolsky

35

hallidavejpalecek有一个正确的想法(遍历数组),但是它们没有利用ArrayList:提供的功能:由于在这种情况下列表的大小是已知的,因此在创建时应指定它ArrayList

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

这样,不会创建不必要的数组,只能将它们丢弃,ArrayList因为它们会变得太短,并且不会浪费空的“插槽”,这是因为ArrayList高估了其空间需求。当然,如果您继续向列表中添加元素,则需要一个新的后备数组。


1
除非代码被证明是性能热点的一部分,或者期望数组非常大,否则我倾向于忽略长度规范。我认为省略长度会使代码更具可读性。
hallidave

19

较为详细,但这可行:

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

在您的示例中,似乎Arrays.asList()将输入解释为long []数组列表,而不是Longs列表。肯定有点令人惊讶。在这种情况下,自动装箱无法按照您想要的方式工作。


17

另一种可能性是,Guava库将此作为提供Longs.asList(),并为其他基本类型提供类似的实用程序类。

import com.google.common.primitives.Longs;

long[] input = someAPI.getSomeLongs();
List<Long> output = Longs.asList(input);

7

不,没有从原始类型的数组到其带框引用类型的数组的自动转换。你只能做

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

for(long l : input) lst.add(l);

7

该问题询问如何将数组转换为列表。到目前为止,大多数答案都显示了如何创建与数组内容相同的列表,或如何引用第三方库。但是,这种转换有简单的内置选项。其中一些已经在其他答案中得到了概述(例如,这个答案)。但是,我想在这里指出并详细说明实施的某些自由度,并说明潜在的优点,缺点和警告。

至少有两个重要的区别:

  • 结果列表应为数组视图还是列表
  • 无论结果列表应该修改或不

这些选项将在这里快速总结,并且完整的示例程序显示在此答案的底部。


创建新列表与在数组上创建视图

当结果应为列表时,则可以使用其他答案中的一种方法:

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

但是,应该考虑这样做的弊端:具有1000000 long值的数组将占用大约8 MB的内存。新的名单将同时占用大约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

6

Java 8的另一种方式。

long[] input = someAPI.getSomeLongs();
LongStream.of(input).boxed().collect(Collectors.toList()));

6

我正在为这些问题编写一个小型图书馆:

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

以防万一,请在这里检查。


漂亮的图书馆!起初,我不确定它是Java ...我喜欢JQuery风格
Yanick Rochon

4

Java 8的另一种方式

final long[] a = new long[]{1L, 2L};
final List<Long> l = Arrays.stream(a).boxed().collect(Collectors.toList());

1
返回列表(不分配列表)时,我发现我必须做:Arrays.stream(a).boxed().collect(Collectors.<Long>toList());
2015年

1
这与现有答案相同。

3

结合帕维尔和汤姆的答案,我们得到了

   @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);
            }
        };
    }

2

如果您想要类似的语义,Arrays.asList那么您将需要编写(或使用其他人的)客户实现List(可能通过)AbstractList。它的实现应与Arrays.asListbox和unbox值完全相同。


2

您可以使用transmorph

Transmorph transmorph = new Transmorph(new DefaultConverters());
List<Long> = transmorph.convert(new long[] {1,2,3,4}, new TypeReference<List<Long>>() {});

例如,如果source是一个整数数组,它也可以工作。


2

我知道这个问题已经足够老了,但是...您还可以编写自己的转换方法:

@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);

2
关于:catch (ArrayIndexOutOfBoundsException ex) { /* Finished getting array elements */ }您是一个可怕的人。
布兰登·雅伯

嘿,伙计,谢谢你!您的讽刺意味使我找到了更好的解决方案-通过Array.getLength()获得数组的长度。
Pavel Netesa 2012年

1
太棒了!我很高兴我的讽刺态度导致进步,而不仅仅是周围的普遍不愉快:)确实,除非在非常特殊的情况下使用异常不是一个好主意。它们的创建成本非常高。这个新版本很多,速度更快。
布兰登·雅伯

1

虽然可以创建一个新列表并将所有值添加到其中(通过循环或流),但我一直在处理非常大的数组,但性能却很差。因此,我创建了自己的易于使用的原始数组包装器类。

例:

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

注意:我还没有完全测试它,所以如果您发现任何错误/问题,请告诉我。


0

您可以使用LongStream

List<Long> longs = LongStream.of(new long[]{1L, 2L, 3L}).boxed()
                             .collect(Collectors.toList());
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.