在一行中初始化一个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"));

有一个更好的方法吗?


实际上,初始化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 Coin的Collection Literals提案被接受(它将在Java 7中引入,但它不太可能成为Java 8的一部分),那么最好的结果是:

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

不幸的是,它不会帮助你,因为它会初始化一个不可变List而不是一个ArrayList ,而且,它现在还不可用,如果它永远会存在的话。


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

简单的答案

在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 s

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

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

您可以连接Stream s:

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中的某个成员。

你最可能没有做的事。

通常你应该只使用你将要使用的最普通的接口(例如IterableCollectionList )来声明变量,并用特定的实现(例如ArrayListLinkedListArrays.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

另一个例子是总是声明一个InputStream变量,即使它通常是一个FileInputStream或一个BufferedInputStream ,因为有一天很快你或其他人会想使用其他类型的InputStream

链接地址: http://www.djcxy.com/p/725.html

上一篇: Initialization of an ArrayList in one line

下一篇: What's the difference between tilde(~) and caret(^) in package.json?