在一行中初始化一个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中的某个成员。 
你最可能没有做的事。
  通常你应该只使用你将要使用的最普通的接口(例如Iterable , Collection或List )来声明变量,并用特定的实现(例如ArrayList , LinkedList或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
  另一个例子是总是声明一个InputStream变量,即使它通常是一个FileInputStream或一个BufferedInputStream ,因为有一天很快你或其他人会想使用其他类型的InputStream 。 
上一篇: Initialization of an ArrayList in one line
下一篇: What's the difference between tilde(~) and caret(^) in package.json?
