1. Overview
1.概述
In this quick tutorial, we’ll investigate how to initialize a List using one-liners.
在这个快速教程中,我们将研究如何使用单行代码初始化一个List。
2. Create From an Array
2.从一个数组创建
We can create a List from an array. And thanks to array literals, we can initialize them in one line:
我们可以从一个数组中创建一个List。由于有了数组字面,我们可以在一行中初始化它们。
List<String> list = Arrays.asList(new String[]{"foo", "bar"});
We can trust the varargs mechanism to handle the array creation. With that, we can write more concise and readable code:
我们可以信任varargs机制来处理数组的创建。有了这个,我们就可以写出更简洁和可读的代码。
@Test
public void givenArraysAsList_thenInitialiseList() {
List<String> list = Arrays.asList("foo", "bar");
assertTrue(list.contains("foo"));
}
The result instance of this code implements the List interface, but it isn’t a java.util.ArrayList or a LinkedList. Instead, it’s a List backed by the original array, which has two implications that we’ll look at in the rest of this section.
这段代码的结果实例实现了List接口,但它不是java.util.ArrayList或LinkedList。相反,它是一个由原始数组支持的List,这有两个含义,我们将在本节的其余部分进行讨论。
Although the class’s name happens to be ArrayList, it’s in the java.util.Arrays package.
虽然这个类的名字刚好是ArrayList,但它是在java.util.Arrays包中。
2.1. Fixed Size
2.1.固定尺寸
The result instance from Arrays.asList will have a fixed size:
来自Arrays.asList的结果实例将有一个固定大小。
@Test(expected = UnsupportedOperationException.class)
public void givenArraysAsList_whenAdd_thenUnsupportedException() {
List<String> list = Arrays.asList("foo", "bar");
list.add("baz");
}
2.2. Shared Reference
2.2.共享的参考资料
The original array and the list share the same references to the objects:
原始数组和列表共享对对象的引用。
@Test
public void givenArraysAsList_whenCreated_thenShareReference(){
String[] array = {"foo", "bar"};
List<String> list = Arrays.asList(array);
array[0] = "baz";
assertEquals("baz", list.get(0));
}
3. Create From a Stream (Java 8)
3.从一个流中创建(Java 8)
We can easily convert a Stream into any kind of Collection.
我们可以轻松地将Stream转换为任何类型的Collection。
Therefore, with the factory methods for Streams, we can create and initialize lists in one line:
因此,通过Streams的工厂方法,我们可以在一行中创建和初始化列表。
@Test
public void givenStream_thenInitializeList(){
List<String> list = Stream.of("foo", "bar")
.collect(Collectors.toList());
assertTrue(list.contains("foo"));
}
We should note here that Collectors.toList() doesn’t guarantee the exact implementation of the returned List.
我们应该注意到,Collectors.toList()并不能保证返回的List的确切实现。
There’s no general contract about the mutability, serializability or thread safety of the returned instance. So, our code shouldn’t rely on any of these properties.
对于返回的实例的可变性、可序列化或线程安全,没有一般的契约。因此,我们的代码不应该依赖这些属性。
Some sources highlight that Stream.of(…).collect(…) may have a larger memory and performance footprint than Arrays.asList(). But in almost all cases, it’s such a micro-optimization that there is little difference.
一些资料强调,Stream.of(…).collect(…)可能比Arrays.asList()具有更大的内存和性能占用。但是在几乎所有的情况下,这只是一个微观的优化,没有什么区别。
4. Factory Methods (Java 9)
4.工厂方法(Java 9)
JDK 9 introduces several convenient factory methods for collections:
JDK 9为集合引入了几种方便的工厂方法。
List<String> list = List.of("foo", "bar", "baz");
Set<String> set = Set.of("foo", "bar", "baz");
One important detail is that the returned instances are immutable. Beyond that, the factory methods have several advantages in space efficiency and thread safety.
一个重要的细节是,返回的实例是不可更改的。除此之外,工厂方法在空间效率和线程安全方面有几个优势。
This topic is explored more in this article.
在这篇文章中会对这个话题进行更多的探讨。
5. Double-Brace Initialization
5.双轨制初始化
In several places, we can find a method called double-brace initialization, which looks like this:
在好几个地方,我们可以找到一种叫做 “双支架初始化 “的方法,它看起来像这样。
@Test
public void givenAnonymousInnerClass_thenInitialiseList() {
List<String> cities = new ArrayList() {{
add("New York");
add("Rio");
add("Tokyo");
}};
assertTrue(cities.contains("New York"));
}
The name “double-brace initialization” is quite misleading. While the syntax may look compact and elegant, it dangerously hides what is going on under the hood.
“双括号初始化 “这个名字很容易让人误解。虽然这个语法看起来紧凑而优雅,但它危险地掩盖了引擎盖下正在发生的事情。
There isn’t actually a double-brace syntax element in Java; those are two blocks formatted intentionally this way.
实际上,在Java中并没有一个双括号的语法元素;那些是故意这样格式化的两个块。
With the outer braces, we declare an anonymous inner class that will be a subclass of the ArrayList. We can declare the details of our subclass inside these braces.
通过外层大括号,我们声明了一个匿名的内层类,它将是ArrayList的子类。我们可以在这些大括号中声明我们子类的细节。
As usual, we can use instance initializer blocks, and that is where the inner pair of braces comes from.
像往常一样,我们可以使用实例初始化块,这就是内部一对大括号的由来。
The brevity of this syntax is tempting. However, it’s considered an anti-pattern.
这种语法的简洁性是很诱人的。然而,它被认为是一种反模式。
To read more about double-brace initialization, have a look at our article here.
要阅读更多关于双括号初始化的内容,请看我们的文章这里。
6. Conclusion
6.结语
Modern Java offers several options to create a Collection in one line. The method we choose is almost entirely down to personal preference rather than technical reasoning.
现代Java提供了几种选择,可以在一行中创建一个Collection。我们选择的方法几乎完全取决于个人偏好,而不是技术推理。
An important takeaway is that, although it looks graceful, the anti-pattern of anonymous inner class initialization (aka double brace) has many negative side effects.
一个重要的启示是,尽管它看起来很优雅,但匿名内部类初始化的反模式(又称双括号)有许多负面的副作用。
As always, the code is available over on GitHub.
像往常一样,代码可在GitHub上获得。