在一行中初始化一个ArrayList

java collections arraylist initialization


我想建立一个选项清单,以便进行测试。一开始,我是这样做的。

ArrayList<String> places = new ArrayList<String>();
places.add("Buenos Aires");
places.add("Córdoba");
places.add("La Plata");

然后,我将代码重构如下。

ArrayList<String> places = new ArrayList<String>(
    Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));

有没有更好的方法?




Answer 1 coobird


实际上,初始化 ArrayList 的“最佳”方法可能是您编写的方法,因为它不需要以任何方式创建新的 List

ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");

不足之处是要引用该 list 实例需要大量输入。

还有其他的选择,比如用实例初始化器做一个匿名的内类(也就是所谓的 "双括号初始化")。

ArrayList<String> list = new ArrayList<String>() {{
    add("A");
    add("B");
    add("C");
}};

但是,我不太喜欢这种方法,因为最终得到的是 ArrayList 的子类,该子类具有实例初始化程序,并且创建该类只是为了创建一个对象-对我来说似乎有点过头了。

如果接受了针对Project CoinCollection Literals提案(该提案原定在Java 7中引入,但也不太可能成为Java 8的一部分):

List<String> list = ["A", "B", "C"];

不幸的是,它在这里无济于事,因为它将初始化一个不可变的 List 而不是 ArrayList ,而且,如果可以的话,它还不可用。




Answer 2 Tom


如果仅将其声明为 List ,则会更简单-它必须是ArrayList吗?

List<String> places = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");

或者如果你只有一个元素。

List<String> places = Collections.singletonList("Buenos Aires");

这意味着 places不变的(尝试更改位置将导致引发 UnsupportedOperationException 异常)。

要创建一个具体的 ArrayList 可变列表,可以从不可变列表创建 ArrayList

ArrayList<String> places = new ArrayList<>(Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));



Answer 3 Christoffer Hammarström


简单的答案是

Java 9或更高版本中,添加 List.of() 之后:

List<String> strings = List.of("foo", "bar", "baz");

Java 10或更高版本中,可以使用 var 关键字来缩短它。

var strings = List.of("foo", "bar", "baz");

这将为您提供一个不变的 List ,因此无法更改。
这是你在大多数情况下想要的,你要预置它。


Java 8或更早。

List<String> strings = Arrays.asList("foo", "bar", "baz");

这将为您提供由数组支持的 List ,因此它不能更改长度。
但是您可以调用 List.set ,所以它仍然是可变的


您可以使用静态导入使 Arrays.asList 变得更短:

List<String> strings = asList("foo", "bar", "baz");

静态导入。

import static java.util.Arrays.asList;  

任何现代IDE都会建议并自动为你做。
例如,在IntelliJ IDEA中,按 Alt+Enter 并选择“ Static import method...


但是,我不建议将 List.of 方法缩短为 of ,因为这会造成混淆。
List.of 已经足够短了,而且读起来也不错。


使用 Stream 小号

为什么它必须是 List
在Java 8或更高版本中,您可以使用更灵活的 Stream

Stream<String> strings = Stream.of("foo", "bar", "baz");

您可以串联 Stream

Stream<String> strings = Stream.concat(Stream.of("foo", "bar"),
                                       Stream.of("baz", "qux"));

或者,您可以从 Stream 转到 List

import static java.util.stream.Collectors.toList;

List<String> strings = Stream.of("foo", "bar", "baz").collect(toList());

但最好是,仅使用 Stream 而不将其收集到 List


如果您确实确实需要 java.util.ArrayList

(您可能没有。)
引用JEP 269(重点是我的话):

少量用例用于使用预定义的值集初始化可变集合实例。通常最好将这些预定义值放在不可变的集合中,然后通过复制构造函数初始化可变集合。


如果您要预填充 ArrayList 然后又添加到它(为什么?),请使用

ArrayList<String> strings = new ArrayList<>(List.of("foo", "bar"));
strings.add("baz");

或在Java 8或更早的版本中。

ArrayList<String> strings = new ArrayList<>(asList("foo", "bar"));
strings.add("baz");

或使用 Stream

import static java.util.stream.Collectors.toCollection;

ArrayList<String> strings = Stream.of("foo", "bar")
                             .collect(toCollection(ArrayList::new));
strings.add("baz");

但是同样,最好直接使用 Stream 而不是将其收集到 List 中。


程序对接口,而不是对实现

您说过已在代码中将列表声明为 ArrayList ,但是仅当使用的不是 ListArrayList 成员时,才应该这样做。

而你很可能不会这样做。

通常,您只应通过将要使用的最通用的接口(例如 IterableCollectionList )声明变量,并使用特定的实现(例如 ArrayListLinkedListArrays.asList() )对其进行初始化。

否则你就会把你的代码限制在那个特定的类型上,想改的时候就难了。

例如,如果要将 ArrayList 传递给 void method(...)

// Iterable if you just need iteration, for (String s : strings):
void method(Iterable<String> strings) { 
    for (String s : strings) { ... } 
}

// Collection if you also need .size(), .isEmpty(), or .stream():
void method(Collection<String> strings) {
    if (!strings.isEmpty()) { strings.stream()... }
}

// List if you also need .get(index):
void method(List<String> strings) {
    strings.get(...)
}

// Don't declare a specific list implementation
// unless you're sure you need it:
void method(ArrayList<String> strings) {
    ??? // You don't want to limit yourself to just ArrayList
}

另一个示例将始终将变量声明为 InputStream ,即使它通常是 FileInputStreamBufferedInputStream ,因为有一天您或其他人将想要使用其他类型的 InputStream




Answer 4 Randyaa


如果你需要一个简单的大小1的列表。

List<String> strings = new ArrayList<String>(Collections.singletonList("A"));

如果你需要一个多个对象的列表。

List<String> strings = new ArrayList<String>();
Collections.addAll(strings,"A","B","C","D");



Answer 5 Paweł Adamski


使用番石榴,您可以编写:

ArrayList<String> places = Lists.newArrayList("Buenos Aires", "Córdoba", "La Plata");

在Guava中,还有其他有用的静态构造函数。您可以在这里阅读有关它们的信息。