从数组创建ArrayList

4087

给定一个类型为 Element[] 的数组:

Element[] array = {new Element(1), new Element(2), new Element(3)};

如何将这个数组转换为类型为ArrayList<Element>的对象?

ArrayList<Element> arrayList = ???;
42个回答

5102
你可以使用以下指示:
new ArrayList<>(Arrays.asList(array));

404
没错。而且在最常见的情况下,如果你只需要一个列表,那么new ArrayList调用也是不必要的。 - Calum
163
可以这样翻译:使用List<ClassName> list = Arrays.asList(array)即可,此代码可以将数组转换为列表。 - Pool
277
在Alex Miller的回答中已经指出,如果不将“Arrays.asList(array)”传递给新的“ArrayList”对象,则列表的大小会固定。使用ArrayList的一个更常见的原因是能够动态改变其大小,而你的建议会阻止这一点。@Calum和@Pool,请注意。 - Code Jockey
147
Arrays.asList()是一个糟糕的函数,你不应该直接使用它的返回值。它会破坏List模板,因此即使它看起来多余,也要按照这里指示的形式使用它。好的回答。 - Adam
87
@Adam 请研究java.util.List的javadoc。add的合同允许它们抛出UnsupportedOperationException异常。http://docs.oracle.com/javase/7/docs/api/java/util/List.html#add%28E%29 诚然,从面向对象的角度来看,为了使用集合,很多时候你必须知道具体的实现方式,这是为了保持框架的简单性而做出的务实设计选择。 - lbalazscs
显示剩余5条评论

1004

给定:

Element[] array = new Element[] { new Element(1), new Element(2), new Element(3) };

最简单的答案是这样做:

List<Element> list = Arrays.asList(array);

这个方法将能够正常工作。但需要注意以下几点:

  1. asList() 返回的列表大小是固定的。因此,如果您想在代码中添加或删除返回的列表元素,则需要将其包装在一个新的 ArrayList 中。否则会抛出一个 UnsupportedOperationException 异常。
  2. asList() 返回的列表由原始数组支持。如果修改原始数组,则列表也将被修改。这可能会令人惊讶。

45
Arrays.asList() 只是通过包装现有的数组来创建一个ArrayList,因此它的时间复杂度为 O(1)。 - Alex Miller
36
在一个新的ArrayList中进行包装将导致对固定大小列表的所有元素进行迭代并添加到新的ArrayList中,因此时间复杂度为O(n)。 - Alex Miller
9
澄清一下,Arrays.asList() 创建的是 java.util.Arrays.ArrayListjava.util.Arrays 中的静态嵌套类),而不是 java.util.ArrayList - Christoffer Hammarström

402

(虽然这是一篇旧帖子,但是没有提到Guava或其他库以及其他细节)

如果可以的话,请使用Guava

值得注意的是,Guava的方法大大简化了这些嬉皮士:

用法

对于不可变列表

使用ImmutableList类及其of()copyOf()工厂方法 (元素不能为null)

List<String> il = ImmutableList.of("string", "elements");  // from varargs
List<String> il = ImmutableList.copyOf(aStringArray);      // from array

对于可变列表

使用Lists类及其newArrayList()工厂方法:

List<String> l1 = Lists.newArrayList(anotherListOrCollection);    // from collection
List<String> l2 = Lists.newArrayList(aStringArray);               // from array
List<String> l3 = Lists.newArrayList("or", "string", "elements"); // from varargs

请注意其他类中其他数据结构的类似方法,例如在Sets中。

为什么选择Guava?

主要吸引力可能在于减少由于泛型而导致的混乱,因为Guava的工厂方法的使用大多数情况下允许推断类型。然而,自从Java 7推出了新的钻石操作符后,这个论点的说服力已经减弱了。

但这并不是唯一的原因(而且Java 7还没有到处都有):简写语法也非常方便,而且像上面所示的方法初始化器可以编写更具表现力的代码。您可以在一个Guava调用中完成当前Java集合需要2个调用的操作。


如果你无法...

对于不可变列表

使用JDK的Arrays类及其asList()工厂方法,结合Collections.unmodifiableList()进行包装:

List<String> l1 = Collections.unmodifiableList(Arrays.asList(anArrayOfElements));
List<String> l2 = Collections.unmodifiableList(Arrays.asList("element1", "element2"));

请注意,asList()返回的类型是使用具体的ArrayList实现的List,但它不是java.util.ArrayList。它是一个内部类型,模拟了一个ArrayList,但实际上直接引用传递的数组并使其“写入”(修改反映在数组中)。
通过简单地扩展AbstractList,它禁止通过一些List API方法进行修改(因此,添加或删除元素是不受支持的),但允许调用set()来覆盖元素。因此,这个列表并不是真正的不可变的,对asList()的调用应该用Collections.unmodifiableList()包装起来。
如果需要一个可变列表,请参见下一步。
与上面相同,但用实际的java.util.ArrayList包装:
List<String> l1  = new ArrayList<String>(Arrays.asList(array));    // Java 1.5 to 1.6
List<String> l1b = new ArrayList<>(Arrays.asList(array));          // Java 1.7+
List<String> l2  = new ArrayList<String>(Arrays.asList("a", "b")); // Java 1.5 to 1.6
List<String> l2b = new ArrayList<>(Arrays.asList("a", "b"));       // Java 1.7+

教育目的:老式手动方式

// for Java 1.5+
static <T> List<T> arrayToList(final T[] array) {
  final List<T> l = new ArrayList<T>(array.length);

  for (final T s : array) {
    l.add(s);
  }
  return (l);
}

// for Java < 1.5 (no generics, no compile-time type-safety, boo!)
static List arrayToList(final Object[] array) {
  final List l = new ArrayList(array.length);

  for (int i = 0; i < array.length; i++) {
    l.add(array[i]);
  }
  return (l);
}

33
注意,Arrays.asList 返回的 List 是可变的,因为您仍然可以使用 set 方法更改元素,它只是不可调整大小。如果要创建不可变列表并且没有 Guava 库,则可以考虑使用 Collections.unmodifiableList - Paul Bellora

254

由于这个问题相当老,让我感到惊讶的是还没有人提出最简单的形式:

List<Element> arraylist = Arrays.asList(new Element(1), new Element(2), new Element(3));

从Java 5开始,Arrays.asList()方法接受可变参数(varargs),您无需显式构造数组。


9
特别是,List<String> a = Arrays.asList("first","second","third") - 18446744073709551615

228
new ArrayList<T>(Arrays.asList(myArray));

请确保myArrayT的类型相同。例如,如果您尝试从int数组创建List<Integer>,则会收到编译器错误。


114

另一种方式(虽然在性能方面基本相当于new ArrayList(Arrays.asList(array))解决方案):

Collections.addAll(arraylist, array);

在Java 16之前,javadoc声明:此便捷方法的行为与c.addAll(Arrays.asList(elements))相同,但是该方法在大多数实现下可能运行显着更快 - cachius
请参考此问题进行比较讨论。 - cachius

114

Java 9

Java9中,你可以使用 List.of 静态工厂方法来创建一个List字面值。类似于以下内容:

List<Element> elements = List.of(new Element(1), new Element(2), new Element(3));

这将返回一个包含三个元素的不可变列表。如果您想要一个可变列表,请将该列表传递给ArrayList构造函数:
new ArrayList<>(List.of(// elements vararg))

JEP 269:集合的便利工厂方法

JEP 269Java Collections API提供了一些便利的工厂方法。这些不可变的静态工厂方法已经内置在Java 9及更高版本的ListSetMap接口中。


1
List.of()不会返回java.util.ArrayList的实例,正如原问题所请求的那样。因此,只有第二个选项是有效答案。 - tquadrat

94

你可能只需要一个列表,而不是ArrayList。在这种情况下,您可以这样做:

List<Element> arraylist = Arrays.asList(array);

8
这将由原始的输入数组支持,这就是为什么你(可能)想要将它包装在一个新的ArrayList中的原因。 - Bill the Lizard
17
请注意这个解决方案。如果你看一下,Arrays方法并没有返回一个真正的java.util.ArrayList。它返回的是一个内部类,该内部类实现了必需的方法,但你不能更改列表中的成员。它只是一个围绕数组的包装器。 - Mikezx6r
13
@Mikezx6r提到的内容需要作出一点纠正:它是一个固定大小的列表。您可以更改列表中的元素(使用“set”方法),但不能更改列表的大小(不能添加或删除元素)! - user85421
1
是的,但这取决于您想对列表做什么。值得注意的是,如果 OP 只想遍历元素,则根本不需要转换数组。 - PaulMurrayCbr
1
@monksy 不行,就像之前说的一样,这是一种不同类型的“ArrayList”。 - glglgl
显示剩余2条评论

78

另一个更新,快要结束2014年了,你也可以使用Java 8来做到这一点:

ArrayList<Element> arrayList = Stream.of(myArray).collect(Collectors.toCollection(ArrayList::new));

如果只使用 List,就可以节省一些字符。

List<Element> list = Stream.of(myArray).collect(Collectors.toList());

10
最好不要依赖具体实现,但是Collectors.toList()方法实际上返回的是一个ArrayList - bcsb1001
不正确地使用Stream.of(...); 这将创建一个单元素流。请改用Arrays.stream。 - Patrick Parker
我认为两个选项都是有效的,但 Arrays.stream 稍微更好一些,因为你可以使用带有“start”、“end”参数的重载方法创建固定大小的流。请参阅:https://dev59.com/dV4c5IYBdhLWcg3weaP8#27888447 - yamilmedina

49

如果您使用:

new ArrayList<T>(Arrays.asList(myArray));

您可以创建并填充两个列表!重复填充一个大列表正是您不想做的,因为每次需要扩展容量时都会创建另一个Object[]数组。

幸运的是,JDK实现很快,Arrays.asList(a[])非常出色。它创建了一种名为 Arrays.ArrayList 的 ArrayList,其中 Object[] 数据直接指向数组。

// in Arrays
@SafeVarargs
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}
//still in Arrays, creating a private unseen class
private static class ArrayList<E>

    private final E[] a;    
    ArrayList(E[] array) {
        a = array; // you point to the previous array
    }
    ....
}
危险的一面是如果您更改了初始数组,则会更改列表!您确定要这样吗?也许是,也许不是。
如果不是,最易理解的方法是执行以下操作:
ArrayList<Element> list = new ArrayList<Element>(myArray.length); // you know the initial capacity
for (Element element : myArray) {
    list.add(element);
}

或者像@ glglgl所说的那样,您可以创建另一个独立的ArrayList:

new ArrayList<T>(Arrays.asList(myArray));

我喜欢使用CollectionsArrays或Guava。但如果不适合或者你感觉不舒服,就写另一行不太优美的代码。


1
我看不出你在答案末尾的循环和你不建议使用的 new ArrayList<T>(Arrays.asList(myArray)); 部分之间的根本区别。两者都做了相同的事情,并具有相同的复杂度。 - glglgl
创建的集合在数组开头创建一个指针。我的循环为每个数组成员创建许多指针。因此,如果原始数组发生更改,我的指针仍然指向先前的值。 - Nicolas Zozol
1
new ArrayList<T>(Arrays.asList(myArray)); 的作用是将 asList 复制到一个 ArrayList 中... - glglgl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接