当前位置: 首页 > 知识库问答 >
问题:

在一行中初始化ArrayList

梁盛
2023-03-14

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

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

有更好的方法吗?

共有3个答案

丁慈
2023-03-14
var strings = List.of("foo", "bar", "baz");

这将为您提供一个不可变的列表,因此它无法更改
在大多数情况下,在预填充时,这就是您想要的。

如果使用Java9,则不能使用var关键字:

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

这将为您提供一个由数组支持的列表*,因此它无法更改长度
但是你可以调用列表。集合(…) ,所以它仍然是可变的。

*实现细节:它是一个私有的嵌套类在java.util.数组中,名为ArrayList
这是一个不同于java.util.ArrayList的类,尽管它们的名称很简单都是一样的。

你可以制作Java8数组。asList使用静态导入时更短:

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

任何现代IDE都会为您提供建议。

我不建议静态导入List.of方法作为,因为它很混乱。

*例如,在IntelliJ IDEA中,按Alt Enter并选择静态导入方法...

为什么它必须是一个列表
对于Java 8或更高版本,您可以使用更灵活的流:

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

您可以连接s:

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

但最好只使用Stream而不将其收集到List

如果既要预填充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");

但是,最好直接使用Stream,而不是将其收集到List

*您可能不需要特定的数组列表。引用JEP 269:

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

(强调我的)

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

而你很可能没有这么做。

通常,您只需通过将要使用的最通用接口(例如IterableCollection、或List)声明变量,并使用特定实现(例如ArrayListLinkedListArrays.asList())初始化它们。

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

例如,如果您将一个ArrayList传递给一个vol方法(...)

// 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,即使它通常是FileInputStreamBufferedInputStream,因为不久的将来,您或其他人会想使用其他类型的InputStream

潘琨
2023-03-14

实际上,初始化ArrayList的最佳方式可能是您编写的方法,因为它不需要以任何方式创建新的List

ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");

问题在于,引用列表实例需要大量的输入。

还有其他选择,例如使用实例初始值设定项创建匿名内部类(也称为“双括号初始化”):

ArrayList<String> list = new ArrayList<String>() {{
    add("A");
    add("B");
    add("C");
}};

然而,我不太喜欢这种方法,因为你最终得到的是ArrayList的一个子类,它有一个实例初始值设定项,而创建这个类只是为了创建一个对象——这对我来说似乎有点过头了。

如果项目硬币的收藏文字提案被接受(它计划在Java7推出,但也不太可能成为Java8的一部分。):

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

不幸的是,它在这里对您没有帮助,因为它将初始化不可变的List,而不是ArrayList,此外,它还不可用,如果它将来会可用的话。

丁灿
2023-03-14

如果您只是将其声明为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"));
 类似资料:
  • 问题内容: 我想创建用于测试目的的选项列表。首先,我这样做: 然后,我将代码重构如下: 有一个更好的方法吗? 问题答案: 实际上,初始化的“最佳”方法可能ArrayList是你编写的方法,因为它无需以List任何方式创建新方法: 问题是引用该实例需要大量输入。 还有其他选择,例如使用实例初始化程序(也称为“双括号初始化”)创建匿名内部类: 但是,我不太喜欢这种方法,因为最终得到的是ArrayLis

  • 据我所知,在Java11中,这两个操作可以在一行中完成,不是吗?

  • 问题内容: 我有一个初始化为的变量: 问题是,在某个时候,我需要重置此变量,以便在更改后可以再次初始化。但是如果我将类设置为可选的话,LLVM在尝试将它设置为时会给我一个错误。如果我只是使用将其重置在代码中的某个位置,它将最终显示为。 有没有一种方法可以使用并允许自己重置? 问题答案: 懒惰是明确的仅一次初始化。您要采用的模型可能只是按需初始化模型: 现在,只要是,它会被初始化并返回。可以通过设置

  • 原始关闭原因未解决 如何在一行中初始化of?

  • Initialization 初始化 Although it doesn’t look superficially very different from initialization in C or C++, initialization in Go is more powerful. Complex structures can be built during initialization a

  • 初始化是为类、结构体或者枚举准备实例的过程。这个过需要给实例里的每一个存储属性设置一个初始值并且在新实例可以使用之前执行任何其他所必须的配置或初始化。 你通过定义初始化器来实现这个初始化过程,它更像是一个用来创建特定类型新实例的特殊的方法。不同于 Objective-C 的初始化器,Swift 初始化器不返回值。这些初始化器主要的角色就是确保在第一次使用之前某类型的新实例能够正确初始化。 类类型的