题 在一行中初始化ArrayList


我想创建一个用于测试目的的选项列表。起初,我这样做了:

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

有一个更好的方法吗?


2164
2018-06-17 04:10


起源


如果这是用于单元测试,请尝试groovy for swing。您可以在测试Java代码时编写测试代码,然后使用 ArrasyList<String> places = ["Buenos Aires", "Córdoba", "La Plata"] - ripper234
在Java SE 7中,您可以使用一组空的类型参数(<>)替换构造函数的参数化类型:Map <String,List <String >> myMap = new HashMap <>(); - Rose
也可以看看 stackoverflow.com/questions/157944/create-arraylist-from-array - Christoffer Hammarström
使用双支撑初始化:) - Mohammad Reza Khatami
Stream.of(“val1”,“val2”)。collect(Collectors.toList()); //创建ArrayList,Java8解决方案。 - torina


答案:


实际上,可能是初始化的“最佳”方式 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 它有一个实例初始化器,并且创建该类只是为了创建一个对象 - 这对我来说似乎有点过分。

如果是的话,本来会很棒的 Collection Literals提案 对于 项目硬币 被接受(它被定义为在Java 7中引入,但它也不可能成为Java 8的一部分。):

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

不幸的是,它不会帮助你,因为它将初始化一个不可变的 List 而不是一个 ArrayList而且,它还没有,如果有的话。


1627
2018-06-17 04:13



看到 stackoverflow.com/questions/924285 有关双支撑初始化,优缺点的更多信息。 - Eddie
@Eddie:很好地调用链接 - 关于双括号初始化的一个句子不足以完全描述它。 - coobird
仅当您不依赖于自动装箱列表<Double> list = [1.0,2.0,3.0]时才有效;失败。 - Richard B
好吧,只是去展示 - 一个男人的语法糖是另一个男人的句法糖尿病。我会远离这些“替代品”。 - corsiKa
由于这个答案是最受欢迎的,并且提到了Project Coin,我认为你应该调用带有List.of(...)语法的java 9: docs.oracle.com/javase/9​​/docs/api/java/util/List.html#of-E...- - Asaf


如果你只是声明它是一个更简单 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"));

1734
2018-06-17 04:15



@Marcase:你能改变你的类来使用List而不是ArrayList吗? - Lawrence Dol
根据我的回答,如果你没有使用特定的方法 ArrayList,将声明更改为更好的设计 List。指定接口,而不是实现。 - Christoffer Hammarström
@ChristofferHammarström:如果他将声明改为 名单 并使用 List <String> places = Arrays.asList(...); 他将无法使用 places.add( “布拉布拉”) - maks
要清楚, asList(...) 返回固定大小 List 这种情况在变异等操作上爆炸 remove 和 clear事情 List 合同要求支持。即使你把声明留作了 List,你需要使用 List l = new ArrayList(asList(...)) 为了获得一个不会抛出OperationNotSupported异常的对象。 Liskov Substitution Principle是谁? - Splash
@溅: remove 和 clear 是可选操作 List所以 asList(...) 确实遵守了合同。 OP没有说他需要在以后添加更多元素,这个例子只是一个 List 需要使用三个元素进行初始化。 - Christoffer Hammarström


简单的答案

在Java 8或更早版本中:

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

这会给你一个 List 由数组支持,所以它不能改变长度。
但你可以打电话 List.set,所以它仍然是可变的。


在Java 9中:

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

这将给你一个不可改变的 List,所以它无法改变。
在您预先填充它的大多数情况下,这是您想要的。


答案越短

你(们)能做到 Arrays.asList 静态导入甚至更短:

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

静态导入:

import static java.util.Arrays.asList;  

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


但是,我不建议缩短Java 9 List.of 方法,因为刚刚 of 变得混乱。
List.of 已经很短了,读起来也不错。


运用 Stream小号

为什么它必须是一个 List
使用Java 8或更高版本,您可以使用 Stream 哪个更灵活:

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

你可以连接 StreamS:

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

或者你可以去一个 Stream 到了 List

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

但最好是,只需使用 Stream 没有把它收集到一个 List


如果你  特别需要一个 java.util.ArrayList

(你可能没有。)
去引用 JEP 269 (强调我的):

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


如果你想  预填充 ArrayList   之后添加(为什么?),使用

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

或者在Java 9中:

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

或使用 Stream

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

但同样,最好只使用 Stream 直接而不是收集它 List


编程到接口,而不是实现

你说你已经将列表声明为 ArrayList 在你的代码中,但是你应该只在你使用某些成员时才这样做 ArrayList 那不是 List

你很可能不会这样做。

通常你应该通过你将要使用的最通用的接口声明变量(例如 IterableCollection, 要么 List),并用具体实现初始化它们(例如, ArrayListLinkedList 要么 Arrays.asList())。

否则,您将代码限制为特定类型,并且在您需要时更难更改。

例如:

// Iterable if you just need iteration, for (String s : strings):
Iterable<String> strings = new ArrayList<>();   

// Collection if you also need .size() or .stream():
Collection<String> strings = new ArrayList<>(); 

// List if you also need .get(index):
List<String> strings = new ArrayList<>();       

// Don't declare a specific list implementation
// unless you're sure you need it:
ArrayList<String> strings = new ArrayList<>();  // You don't need ArrayList

另一个例子是总是声明变量a InputStream 即使它通常是一个 FileInputStream 或者a BufferedInputStream,因为有一天你或其他人会想要使用其他一些 InputStream


582
2017-09-09 12:33



真的非常感谢你。我试图在我的代码中省略'static'import,但编译器没有任何东西。为什么静态代码必须工作? - jollyroger
@海盗旗: Arrays.asList 是一种静态方法。看到 docs.oracle.com/javase/1.5.0/docs/guide/language/... - Christoffer Hammarström
@ChristofferHammarström在这种情况下,我的新手头脑告诉我,静态导入与全局变量以及与此类用法相关的危险非常相似。这个假设是否正确,这也是上述类似答案获得更多选票的原因吗? - jollyroger
如果您不想要静态导入,您还可以定义静态asList方法的完整路径,如下所示:List <String> strings = java.util.Arrays.asList(“”,“”); - Geert Weening
或者你可以使用import java.util.Arrays;和Arrays.asList(“”,“”);您不必使用静态导入。您不必使用完整路径。静态方法不关心导入。如果您使用实例来查找它们,他们会感到恼火。 - candied_orange


如果您需要一个大小为1的简单列表:

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

如果需要几个对象的列表:

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

100
2017-08-30 04:33





番石榴 你可以写:

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

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


52
2017-07-29 13:24



我很确定你能做到这一点 java.util.Arrays 如, List<String> names = Arrays.asList("Beckah", "Sam", "Michael"); - beckah
@beckah方法Arrays.asLists创建List类型的对象,而问题是关于创建ArrayList - Paweł Adamski
这种方法实际上并不十分有用,将来很可能会被弃用。 - shmosel


集合文字没有进入Java 8,但是可以使用Stream API在一个相当长的行中初始化列表:

List<String> places = Stream.of("Buenos Aires", "Córdoba", "La Plata").collect(Collectors.toList());

如果你需要确保你的 List 是一个 ArrayList

ArrayList<String> places = Stream.of("Buenos Aires", "Córdoba", "La Plata").collect(Collectors.toCollection(ArrayList::new));

32
2018-04-03 23:21





import com.google.common.collect.ImmutableList;

....

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

26
2018-05-12 13:14



我不想添加新的依赖项来做到这一点。 - Macarse
那是一样的 Collections.unmodifiableList(Arrays.asList("Buenos Aires", "Córdoba", "La Plata")),成为 unmodifiableList(asList("Buenos Aires", "Córdoba", "La Plata")) 使用静态导入。您不需要Google Collections。 - Christoffer Hammarström
不,这不一样。由于ImmutableList在不可修改的列表中将其伪装成普通列表时在结果类型中记录其不变性。 - David Pierre
google集合还提供了可变数组列表而不是不可变数组:List <String> = Lists.newArrayList(“Buenos Aires”,“Córdoba”,“La Plata”); - L. Holanda
你要通过那个 ImmutableList 采取其他方法 List,无论如何你已经失去了那份文件。 - Christoffer Hammarström