这可能是一个简单的问题,但是我的第一次尝试完全没有奏效。我想采用一系列原始long并将其转换为一个列表,我试图这样做:
long[] input = someAPI.getSomeLongs();
List<Long> inputAsList = Arrays.asList(input); //Total failure to even compile!
这样做的正确方法是什么?
答案 0 :(得分:105)
我发现使用apache commons lang ArrayUtils(JavaDoc,Maven dependency)
很方便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);
编辑已更新,可根据评论和其他修正提示完整转换为列表。
答案 1 :(得分:99)
从Java 8开始,您现在可以使用流:
long[] arr = {1,2,3,4};
List<Long> list = Arrays.stream(arr).boxed().collect(Collectors.toList());
答案 2 :(得分:37)
import java.util.Arrays;
import org.apache.commons.lang.ArrayUtils;
List<Long> longs = Arrays.asList(ArrayUtils.toObject(new long[] {1,2,3,4}));
答案 3 :(得分:33)
hallidave和jpalecek有一个正确的想法 - 迭代一个数组 - 但他们没有利用ArrayList
提供的功能:因为的大小列表已知在这种情况下,您应该在创建ArrayList
。
List<Long> list = new ArrayList<Long>(input.length);
for (long n : input)
list.add(n);
这样,ArrayList
不会创建任何不必要的数组,因为它们太短,并且没有空的“槽”被浪费,因为ArrayList
高估了它的空间需求。当然,如果继续向列表中添加元素,则需要新的后备阵列。
答案 4 :(得分:17)
有点冗长,但这有效:
List<Long> list = new ArrayList<Long>();
for (long value : input) {
list.add(value);
}
在您的示例中,似乎Arrays.asList()将输入解释为long []数组的列表而不是Longs列表。有点令人惊讶,当然。在这种情况下,自动装箱并不像你想要的那样工作。
答案 5 :(得分:17)
作为另一种可能性,the Guava library将此提供为Longs.asList()
,其他基本类型具有类似的实用程序类。
import com.google.common.primitives.Longs;
long[] input = someAPI.getSomeLongs();
List<Long> output = Longs.asList(input);
答案 6 :(得分:7)
不,没有从基本类型数组到其盒装引用类型数组的自动转换。你只能做
long[] input = someAPI.getSomeLongs();
List<Long> lst = new ArrayList<Long>();
for(long l : input) lst.add(l);
答案 7 :(得分:6)
Java 8的另一种方式。
long[] input = someAPI.getSomeLongs();
LongStream.of(input).boxed().collect(Collectors.toList()));
答案 8 :(得分:6)
我正在为这些问题编写一个小型库:
long[] input = someAPI.getSomeLongs();
List<Long> = $(input).toList();
如果你在意,请检查here。
答案 9 :(得分:4)
该问题询问有关如何将数组转换为列表的问题。到目前为止,大多数答案都显示了如何创建与数组相同的内容或引用第三方库的 new 列表。但是,这种转换有简单的内置选项。其中一些已经在其他答案中得到了概述(例如this one)。但我想在这里指出并详细说明实施的某些自由度,并说明潜在的好处,缺点和警告。
至少有两个重要区别:
这里将快速总结这些选项,并在此答案的底部显示完整的示例程序。
在阵列上创建新列表与创建视图
当结果应为新列表时,则可以使用其他答案中的一种方法:
List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());
但是,应该考虑这样做的弊端:具有1000000 long
值的数组将占用大约8 MB的内存。新列表还将 占用大约8 MB。当然,创建此列表时必须遍历整个数组。在许多情况下,根本不需要创建新列表。只需在数组上创建一个视图即可:
// 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!
幸运的是,从视图创建副本(即不受阵列中的修改影响的 new 列表)很简单:
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?
可以在可修改的数组上创建列表视图。这意味着列表中的更改(例如在某个索引处设置新值)将在数组中可见。
但是无法创建可在结构上可修改的列表视图。这意味着不可能执行影响列表的 size 的操作。这仅仅是因为基础 array 的大小无法更改。
以下是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
答案 10 :(得分:3)
结合Pavel和Tom的答案,我们得到了这个
@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);
}
};
}
答案 11 :(得分:3)
使用Java 8的另一个way。
final long[] a = new long[]{1L, 2L};
final List<Long> l = Arrays.stream(a).boxed().collect(Collectors.toList());
答案 12 :(得分: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);
答案 13 :(得分:2)
您可以使用transmorph:
Transmorph transmorph = new Transmorph(new DefaultConverters());
List<Long> = transmorph.convert(new long[] {1,2,3,4}, new TypeReference<List<Long>>() {});
如果source是一个int数组,它也可以工作。
答案 14 :(得分:2)
如果你想要与Arrays.asList
类似的语义,那么你需要编写(或使用别人的)List
的客户实现(可能通过AbstractList
。它应该有很多相同的实现为Arrays.asList
,仅包含box和unbox值。
答案 15 :(得分: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
注意:我还没有完全测试它,所以如果您发现任何错误/问题,请告诉我。
答案 16 :(得分:0)
您可以为此使用LongStream
List<Long> longs = LongStream.of(new long[]{1L, 2L, 3L}).boxed()
.collect(Collectors.toList());