在一行中初始化ArrayList

Mac*_*rse 2626 java collections initialization arraylist

我想创建一个用于测试目的的选项列表.起初,我这样做了:

ArrayList<String> places = new ArrayList<String>();
places.add("Buenos Aires");
places.add("Córdoba");
places.add("La Plata");
Run Code Online (Sandbox Code Playgroud)

然后我重构代码如下:

ArrayList<String> places = new ArrayList<String>(
    Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));
Run Code Online (Sandbox Code Playgroud)

有一个更好的方法吗?

Tom*_*Tom 2058

如果你只是声明它是一个更简单List- 它必须是一个ArrayList吗?

List<String> places = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
Run Code Online (Sandbox Code Playgroud)

或者,如果您只有一个元素:

List<String> places = Collections.singletonList("Buenos Aires");
Run Code Online (Sandbox Code Playgroud)

这意味着它places不可变的(尝试更改它将导致UnsupportedOperationException抛出异常).

ArrayList创建一个具体的可变列表,您可以ArrayList从不可变列表创建一个:

ArrayList<String> places = new ArrayList<>(Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));
Run Code Online (Sandbox Code Playgroud)

  • 根据我的回答,如果你没有使用特定于'ArrayList`的方法,那么将声明更改为`List`会更好.指定接口,而不是实现. (72认同)
  • 为了清楚起见,`asList(...)`返回一个固定大小的`List`,它在`remove`和`clear`之类的变异操作上爆炸,这是`List`合同声称支持的东西.即使你将声明保留为`List`,你也需要使用`List l = new ArrayList(asList(...))`来获取一个不会抛出OperationNotSupported异常的对象.Liskov Substitution Principle是谁? (57认同)
  • @Marcase:你能改变你的类来使用List而不是ArrayList吗? (18认同)
  • @ChristofferHammarström:如果他将声明更改为*List*并使用*List <String> places = Arrays.asList(...);*他将无法使用*places.add("blabla")* (9认同)
  • @Splash:`remove`和`clear`是`List`中的可选操作,所以`asList(...)`确实遵循了契约.OP说他需要在以后添加更多元素,这个例子只是一个需要用三个元素初始化的`List`. (4认同)
  • 是的,我的班级有一个私人的ArrayList &lt;String&gt;。 (2认同)
  • @maks:是的,除了那是因为使用了“ asList(...)”,而不是因为将声明从“ ArrayList”更改为“ List”。我将其表示为“他将*不需要*使用`places.add(“ blabla”)`“。他已经亲自将其更改为`asList(...)`。 (2认同)
  • “-尝试更改它会导致引发异常” &lt;-仅适用于更改列表大小的操作。`places.set(0,“ New York”)`应该可以正常工作。 (2认同)
  • 我每次需要的时候怎么都需要查找如何初始化一个该死的可变数组呢?这据说是最好的方法?多么可怕的语言啊。 (2认同)

coo*_*ird 1935

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

ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
Run Code Online (Sandbox Code Playgroud)

问题是,引用该list实例需要进行相当多的输入.

还有其他选择,例如使用实例初始化程序创建匿名内部类(也称为"双括号初始化"):

ArrayList<String> list = new ArrayList<String>() {{
    add("A");
    add("B");
    add("C");
}};
Run Code Online (Sandbox Code Playgroud)

但是,我不太喜欢那种方法,因为你最终得到的是一个子类,ArrayList它有一个实例初始化器,而这个类只是为了创建一个对象而创建 - 这对我来说似乎有些过分.

什么本来不错了,如果集合字面建议项目硬币被接受(它被提名在Java 7中推出,但它不太可能成为Java 8任一部分.):

List<String> list = ["A", "B", "C"];
Run Code Online (Sandbox Code Playgroud)

不幸的是,它不会帮助你,因为它会初始化一个不可变的List而不是一个ArrayList,而且,它还没有,如果它将会是.

  • 有关双支撑初始化,优缺点的更多信息,请参见http://stackoverflow.com/questions/924285/. (163认同)
  • @Eddie:对链接的良好调用 - 关于双括号初始化的一个句子不足以完全描述它. (6认同)
  • 由于这个答案是最受欢迎的,并且提到了项目硬币,我认为你应该调用带有List.of(...)语法的java 9:https://docs.oracle.com/javase/9​​/docs/api/的-E的Java/UTIL/List.html#...- (5认同)
  • 您不需要第二个 &lt;String&gt;。 (3认同)
  • 仅在不依赖自动装箱列表&lt;Double&gt; list = [1.0,2.0,3.0]的情况下有效;失败。 (2认同)

Chr*_*röm 809

简单的答案

在Java 9或更高版本中:

var strings = List.of("foo", "bar", "baz");
Run Code Online (Sandbox Code Playgroud)

这将给你一个不可变的List,所以它不能改变.
在您预先填充它的大多数情况下,这是您想要的.


Java 8或更早版本:

List<String> strings = List.of("foo", "bar", "baz");
Run Code Online (Sandbox Code Playgroud)

这将为您List提供数组支持,因此无法更改长度.
但你可以打电话List.set,所以它仍然是可变的.


答案越短

Arrays.asList静态导入可以缩短甚至更短:

List<String> strings = Arrays.asList("foo", "bar", "baz");
Run Code Online (Sandbox Code Playgroud)

静态导入:

List<String> strings = asList("foo", "bar", "baz");
Run Code Online (Sandbox Code Playgroud)

任何现代IDE都会建议并自动为您做.
例如,在IntelliJ IDEA中,按,Alt+Enter然后选择Static import method....


但是,我不建议缩短Java 9 List.of方法,因为刚刚of变得混乱.
List.of已经很短了,读得很好.


Streams

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

import static java.util.Arrays.asList;  
Run Code Online (Sandbox Code Playgroud)

你可以连接Streams:

Stream<String> strings = Stream.of("foo", "bar", "baz");
Run Code Online (Sandbox Code Playgroud)

或者你可以从a StreamList:

Stream<String> strings = Stream.concat(Stream.of("foo", "bar"),
                                       Stream.of("baz", "qux"));
Run Code Online (Sandbox Code Playgroud)

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


如果你真的特别需要一个java.util.ArrayList

(你可能没有.)
引用JEP 269(强调我的):

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


如果你想预填充的ArrayList ,并添加到它之后(为什么?),使用

import static java.util.stream.Collectors.toList;

List<String> strings = Stream.of("foo", "bar", "baz").collect(toList());
Run Code Online (Sandbox Code Playgroud)

或者在Java 8或更早版本中:

ArrayList<String> strings = new ArrayList<>(List.of("foo", "bar"));
strings.add("baz");
Run Code Online (Sandbox Code Playgroud)

或使用Stream:

ArrayList<String> strings = new ArrayList<>(asList("foo", "bar"));
strings.add("baz");
Run Code Online (Sandbox Code Playgroud)

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


编程到接口,而不是实现

你说你声明的列表作为ArrayList在你的代码,但只应做,如果你正在使用的一些成员ArrayList,这不是在List.

你很可能不会这样做.

通常你应该只需要声明通过通用接口变量,你要使用(例如Iterable,CollectionList),并与具体的实施对它们进行初始化(例如ArrayList,LinkedListArrays.asList()).

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

例如,如果您要传递ArrayListvoid method(...):

import static java.util.stream.Collectors.toCollection;

ArrayList<String> strings = Stream.of("foo", "bar")
                             .collect(toCollection(ArrayList::new));
strings.add("baz");
Run Code Online (Sandbox Code Playgroud)

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

  • @jollyroger:`Arrays.asList`是一个静态方法.见http://docs.oracle.com/javase/1.5.0/docs/guide/language/static-import.html (3认同)
  • @ChristofferHammarström在这种情况下,我的新手头脑告诉我,静态导入与全局变量和与此类用法相关的风险非常相似。这个假设是正确的吗,也是上述类似答案获得更多投票的原因吗? (2认同)
  • 我认为您在谈论的上述答案是一年前做出的。不,全局变量的问题在于它们是可变的。它们与静态导入无关。 (2认同)
  • 如果您不希望静态导入,则还可以定义静态asList方法的完整路径,如下所示:List &lt;String&gt; strings = java.util.Arrays.asList(“”,“”); (2认同)
  • 或者您可以使用import java.util.Arrays; 和Arrays.asList(“”,“”); 您不必使用静态导入。您不必使用完整路径。静态方法不在乎导入。如果您使用实例来查找它们,它们将变得很烦。 (2认同)
  • @PhilipRego:它是java.util.Arrays。大多数IDE都会为您建议这一点。例如,在IntelliJ IDEA中,当建议使用java.util.Arrays时,请按Alt + Enter。 (2认同)

Ran*_*yaa 108

如果您需要一个大小为1的简单列表:

List<String> strings = new ArrayList<String>(Collections.singletonList("A"));
Run Code Online (Sandbox Code Playgroud)

如果需要多个对象的列表:

List<String> strings = new ArrayList<String>();
Collections.addAll(strings,"A","B","C","D");
Run Code Online (Sandbox Code Playgroud)


Paw*_*ski 55

使用番石榴,你可以写:

ArrayList<String> places = Lists.newArrayList("Buenos Aires", "Córdoba", "La Plata");
Run Code Online (Sandbox Code Playgroud)

在Guava中还有其他有用的静态构造函数.你可以在这里阅读它们.

  • 我很确定您可以仅使用“java.util.Arrays”来完成此操作,例如“List &lt;String&gt;名称= Arrays.asList(“Beckah”,“Sam”,“Michael”);` (2认同)
  • @beckah方法Arrays.asLists创建类型为List的对象,而有关创建ArrayList的问题 (2认同)

Mar*_*ark 32

集合文字没有进入Java 8,但是可以使用Stream API在一个相当长的行中初始化列表:

List<String> places = Stream.of("Buenos Aires", "Córdoba", "La Plata").collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

如果你需要确保你ListArrayList:

ArrayList<String> places = Stream.of("Buenos Aires", "Córdoba", "La Plata").collect(Collectors.toCollection(ArrayList::new));
Run Code Online (Sandbox Code Playgroud)


Geo*_*rge 29

import com.google.common.collect.ImmutableList;

....

List<String> places = ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");
Run Code Online (Sandbox Code Playgroud)

  • 不,这不一样.由于ImmutableList在不可修改的列表中将其伪装成普通列表时在结果类型中记录其不变性. (9认同)
  • 这与`Collections.unmodifiableList(Arrays.asList("Buenos Aires","Córdoba","La Plata"))`相同,后者变为`unmodifiableList(asList("Buenos Aires","Córdoba","La Plata") ))`静态导入.您不需要Google Collections. (6认同)
  • 我不想为了这个而添加新的依赖项. (4认同)
  • 你将把那个`ImmutableList`传递给其他采用`List`的方法,然后你就丢失了那些文档. (3认同)
  • Google集合提供了可变数组列表,而不是不变的列表:List &lt;String&gt; = Lists.newArrayList(“ Buenos Aires”,“Córdoba”,“ La Plata”); (2认同)

Nam*_*man 24

随着Java 9,如建议JDK增强提案- 269,这可以实现使用收集文字现在为-

List<String> list = List.of("A", "B", "C");

Set<String> set = Set.of("A", "B", "C");
Run Code Online (Sandbox Code Playgroud)

此外,类似的方法也适用于Map-

Map<String, String> map = Map.of("k1", "v1", "k2", "v2", "k3", "v3")
Run Code Online (Sandbox Code Playgroud)

这与@coobird所述的Collection Literals 提案类似.在JEP文件中进一步澄清 -


备择方案

语言变化已被多次考虑,并被拒绝:

项目硬币提案,2009年3月29日

项目硬币提案,2009年3月30日

JEP 186关于lambda-dev的讨论,2014年1月至3月

优先考虑语言提案,优先于本消息中概述的基于库的提案.

Related => 在Java 9中重载的方便工厂方法的重点是什么


Jor*_*dão 22

您可以创建工厂方法:

public static ArrayList<String> createArrayList(String ... elements) {
  ArrayList<String> list = new ArrayList<String>();
  for (String element : elements) {
    list.add(element);
  }
  return list;
}

....

ArrayList<String> places = createArrayList(
  "São Paulo", "Rio de Janeiro", "Brasília");
Run Code Online (Sandbox Code Playgroud)

但它并不比你的第一次重构好多少.

为了更大的灵活性,它可以是通用的:

public static <T> ArrayList<T> createArrayList(T ... elements) {
  ArrayList<T> list = new ArrayList<T>();
  for (T element : elements) {
    list.add(element);
  }
  return list;
}
Run Code Online (Sandbox Code Playgroud)

  • @LeoHolanda:我同意,为每件小事创建工厂方法太多了.但是_depending_关于情况,以及该方法将被使用的次数,创建它可能是有意义的.通过创建捕获设计者_intent_的更多_meaningful_方法,创建额外的抽象层意味着_remove_复杂性. (7认同)
  • 回顾一下原来的帖子,它要求在*一行*中进行数组初始化,而不是另外7行。 (2认同)

Moh*_*agi 15

在Java 9中,我们可以轻松地ArrayList在一行中初始化:

List<String> places = List.of("Buenos Aires", "Córdoba", "La Plata");
Run Code Online (Sandbox Code Playgroud)

要么

List<String> places = new ArrayList<>(List.of("Buenos Aires", "Córdoba", "La Plata"));
Run Code Online (Sandbox Code Playgroud)

Java 9的这种新方法与以前的方法相比具有许多优点:

  1. 空间效率
  2. 不变性
  3. 线程安全

有关更多详细信息,请参阅此文章 - > List.of和Arrays.asList有什么区别?


小智 8

只需使用以下代码如下.

List<String> list = new ArrayList<String>() {{
            add("A");
            add("B");
            add("C");
}};
Run Code Online (Sandbox Code Playgroud)

  • @bsd您可以在输入任何方法之前使用此方法声明列表.因此,在定义类变量时,可以将内容添加到列表中,而无需调用方法来执行此操作. (2认同)
  • 尽量避免双括号初始化。看到:http://stackoverflow.com/a/924326/760393 (2认同)

Don*_*aab 8

使用Eclipse Collections(以前的GS Collections),您可以编写以下内容:

List<String> list = Lists.mutable.with("Buenos Aires", "Córdoba", "La Plata");
Run Code Online (Sandbox Code Playgroud)

您还可以更具体地了解类型以及它们是可变的还是不可变的.

MutableList<String> mList = Lists.mutable.with("Buenos Aires", "Córdoba", "La Plata");
ImmutableList<String> iList = Lists.immutable.with("Buenos Aires", "Córdoba", "La Plata");
Run Code Online (Sandbox Code Playgroud)

你也可以用套装和包包做同样的事情:

Set<String> set = Sets.mutable.with("Buenos Aires", "Córdoba", "La Plata");
MutableSet<String> mSet = Sets.mutable.with("Buenos Aires", "Córdoba", "La Plata");
ImmutableSet<String> iSet = Sets.immutable.with("Buenos Aires", "Córdoba", "La Plata");

Bag<String> bag = Bags.mutable.with("Buenos Aires", "Córdoba", "La Plata");
MutableBag<String> mBag = Bags.mutable.with("Buenos Aires", "Córdoba", "La Plata");
ImmutableBag<String> iBag = Bags.immutable.with("Buenos Aires", "Córdoba", "La Plata");
Run Code Online (Sandbox Code Playgroud)

注意:我是Eclipse Collections的提交者.


Ric*_*d B 7

关于最紧凑的方法是:

Double array[] = { 1.0, 2.0, 3.0};
List<Double> list = Arrays.asList(array);
Run Code Online (Sandbox Code Playgroud)


Hen*_*k T 7

这是另一种方式:

List<String> values = Stream.of("One", "Two").collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)


use*_*407 6

(应该是评论,但是太长了,所以新回复).正如其他人所提到的,该Arrays.asList方法是固定大小的,但这不是唯一的问题.它也不能很好地处理继承.例如,假设您有以下内容:

class A{}
class B extends A{}

public List<A> getAList(){
    return Arrays.asList(new B());
}
Run Code Online (Sandbox Code Playgroud)

上面导致编译器错误,因为List<B>(即Arrays.asList返回的内容)不是其子类List<A>,即使您可以将B类型的List<A>对象添加到对象中.要解决这个问题,您需要执行以下操作:

new ArrayList<A>(Arrays.<A>asList(b1, b2, b3))
Run Code Online (Sandbox Code Playgroud)

这可能是最好的方法,特别是.如果你需要一个无界的列表或需要使用继承.


Ran*_*ler 6

List<String> names = Arrays.asList("2", "@2234", "21", "11");
Run Code Online (Sandbox Code Playgroud)


ras*_*dcs 6

您可以使用以下语句:

代码片段:

String [] arr = {"Sharlock", "Homes", "Watson"};

List<String> names = Arrays.asList(arr);
Run Code Online (Sandbox Code Playgroud)

  • 您可以内联第一个表达式以获得紧凑的解决方案:`letters = Arrays.asList(new String[]{"A", "B", "C"});` (2认同)

Ozz*_*zzy 5

汤姆说:

List<String> places = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
Run Code Online (Sandbox Code Playgroud)

但是既然你抱怨想要一个ArrayList,你首先应该知道ArrayList是List的子类,你可以简单地添加这一行:

ArrayList<String> myPlaces = new ArrayList(places);
Run Code Online (Sandbox Code Playgroud)

虽然,这可能会让你抱怨'表现'.

在这种情况下,它对我来说没有意义,为什么,因为你的列表是预定义的,它没有被定义为一个数组(因为在初始化时已知大小).如果这是你的选择:

String[] places = {"Buenos Aires", "Córdoba", "La Plata"};
Run Code Online (Sandbox Code Playgroud)

如果您不关心次要的性能差异,那么您也可以非常简单地将数组复制到ArrayList:

ArrayList<String> myPlaces = new ArrayList(Arrays.asList(places));
Run Code Online (Sandbox Code Playgroud)

好的,但是将来你需要的不仅仅是地名,还需要国家代码.假设这仍然是一个在运行时永远不会改变的预定义列表,那么使用一个enum集合是合适的,如果将来需要更改列表,则需要重新编译.

enum Places {BUENOS_AIRES, CORDOBA, LA_PLATA}
Run Code Online (Sandbox Code Playgroud)

会成为:

enum Places {
    BUENOS_AIRES("Buenos Aires",123),
    CORDOBA("Córdoba",456),
    LA_PLATA("La Plata",789);

    String name;
    int code;
    Places(String name, int code) {
      this.name=name;
      this.code=code;
    }
}
Run Code Online (Sandbox Code Playgroud)

Enum有一个静态values方法,它返回一个数组,其中包含枚举的所有值,例如:

for (Places p:Places.values()) {
    System.out.printf("The place %s has code %d%n",
                  p.name, p.code);
}
Run Code Online (Sandbox Code Playgroud)

在那种情况下,我猜你不需要你的ArrayList.

PS Randyaa演示了另一种使用静态实用程序方法Collections.addAll的好方法.


use*_*421 5

Java 9具有以下创建不可变列表的方法:

List<String> places = List.of("Buenos Aires", "Córdoba", "La Plata");
Run Code Online (Sandbox Code Playgroud)

如果需要,它很容易适应创建一个可变列表:

List<String> places = new ArrayList<>(List.of("Buenos Aires", "Córdoba", "La Plata"));
Run Code Online (Sandbox Code Playgroud)

类似的方法可用于SetMap.


MaF*_*FiA 5

有多种方法可以在一行中创建和初始化列表。一些例子:

//Using Double brace initialization, creates a new (anonymous) subclass of ArrayList
List<String> list1 = new ArrayList<>() {{ add("A");  add("B"); }};

//Immutable List
List<String> list2 = List.of("A", "B");

//Fixed size list. Can't add or remove element, though replacing the element is allowed.
List<String> list3 = Arrays.asList("A", "B");

//Modifiable list
List<String> list4 = new ArrayList<>(Arrays.asList("A", "B"));

//Using Java Stream, no guarantees on the type, mutability, serializability, or thread-safety
List<String> list5 = Stream.of("A", "B").collect(Collectors.toList());

//Thread safe List
List<String> list6 = new CopyOnWriteArrayList<>(Arrays.asList("A", "B"));
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

2863543 次

最近记录:

5 年,9 月 前