简单的答案
Java 9或更高版本:
List<String> strings = List.of("foo", "bar", "baz");
这将为您提供一个不可变的列表,因此无法更改。在大多数情况下,这就是你想要的。
Java 8或更早版本:
List<String> strings = Arrays.asList("foo", "bar", "baz");
这将为您提供一个由数组支持的List*,因此它不能更改长度。但是您可以调用List.set(…),所以它仍然是可变的。
*实现细节:它是java.util.Arrays内部的一个私有嵌套类,名为ArrayList,这是一个与java.util.ArrayList不同的类,尽管它们的简单名称相同。
静态导入
您可以通过静态导入使Java 8 Arrays.asList更短:
import static java.util.Arrays.asList;
...
List<String> strings = asList("foo", "bar", "baz");
任何现代IDE*都会为您建议并执行此操作。
我不建议静态地导入List.of方法,因为它会令人困惑。
*例如,在IntelliJ IDEA中,按Alt+Enter并选择静态导入方法。。。
使用流
为什么必须是列表?对于Java 8或更高版本,您可以使用更灵活的Stream:
Stream<String> strings = Stream.of("foo", "bar", "baz");
您可以连接流:
Stream<String> strings = Stream.concat(Stream.of("foo", "bar"),
Stream.of("baz", "qux"));
或者您可以从“流”转到“列表”:
import static java.util.stream.Collectors.toList;
...
var strings = Stream.of("foo", "bar", "baz").toList(); // Java 16
List<String> strings = Stream.of("foo", "bar", "baz").collect(toList()); // Java 8
但最好只使用流而不将其收集到列表中。
如果您特别需要java.util.ArrayList*
如果要预先填充ArrayList并在之后添加到其中,请使用
List<String> strings = new ArrayList<>(List.of("foo", "bar"));
strings.add("baz");
或Java 8或更早版本:
List<String> strings = new ArrayList<>(asList("foo", "bar"));
strings.add("baz");
或使用流:
import static java.util.stream.Collectors.toCollection;
List<String> strings = Stream.of("foo", "bar")
.collect(toCollection(ArrayList::new));
strings.add("baz");
但同样,最好直接使用流,而不是将其收集到列表中。
*您可能不需要特别的ArrayList。引用JEP 269:
使用预定义的值集初始化可变集合实例有一小组用例。通常最好将这些预定义的值放在不可变集合中,然后通过复制构造函数初始化可变集合。
(强调矿井)
程序到接口,而不是实现
您说过您已经在代码中将列表声明为ArrayList,但只有当您使用的ArrayList的某个成员不在list中时,才应该这样做。
这是你最可能不做的。
通常,您应该只通过要使用的最通用的接口(例如Iterable、Collection或List)声明变量,并使用特定的实现(例如ArrayList、LinkedList或Arrays.asList())初始化它们。
否则,您将代码限制为特定类型,并且在需要更改时将更难更改。
例如,如果要将ArrayList传递给void方法(…):
// 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 random access, .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,即使它通常是FileInputStream或BufferedInputStream,因为很快有一天你或其他人会想要使用其他类型的InputStream。