一行初始化ArrayList


2754

我想创建用于测试目的的选项列表。首先,我这样做:

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

有一个更好的方法吗?


34
如果这是用于单元测试,请尝试进行切槽。您可以在测试Java代码的同时在其中编写测试代码,并使用ArrasyList<String> places = ["Buenos Aires", "Córdoba", "La Plata"]
ripper234 2010年

3
在Java SE 7中,可以用一组空的类型参数(<>)代替构造函数的参数化类型:Map <String,List <String >> myMap = new HashMap <>();。
2015年


2
使用双重支撑初始化:)
Mohammadreza Khatami

8
Stream.of(“ val1”,“ val2”)。collect(Collectors.toList()); //创建ArrayList,Java8解决方案。
torina

Answers:


2022

实际上,初始化的“最佳”方法可能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 CoinCollection Literals提案(该提案原定在Java 7中引入,但也不太可能成为Java 8的一部分):

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

不幸的是,它不会在这里为您提供帮助,因为它将初始化一个不可变的变量List而不是一个ArrayList,而且,如果有的话,它将不可用。


172
有关双括号初始化,优缺点的更多信息,请参见stackoverflow.com/questions/924285
艾迪

6
@Eddie:对链接的呼唤很好-双括号初始化的一句话不足以完全描述它。
coobird

2
仅在不依赖自动装箱列表<Double> list = [1.0,2.0,3.0]的情况下有效;失败。
理查德B

1
您在双列表初始化中缺少分号
Don Larynx

6
由于此答案是最受推崇和提及的Project Coin,因此我认为您应该指出List.of(...)语法附带的Java 9:docs.oracle.com/javase/9​​/docs/api/java/util/ List.html#of-E ...-
Asaf

2153

如果仅将其声明为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"));

18
@Marcase:不能将您的类更改为使用列表而不是ArrayList吗?
劳伦斯·多尔

74
根据我的回答,如果您不使用特定于的方法ArrayList,最好将声明更改为List。指定接口,而不是实现。
ChristofferHammarström,2010年

9
@ChristofferHammarström:如果他将声明更改为List并使用List <String> place = Arrays.asList(...); 他将无法使用places.add(“布拉布拉”)
MAKS

57
只是要清楚,asList(...)返回一个固定大小List是像变异操作炸毁removeclear,事List合同索赔的支持。即使您将声明保留为List,您仍然必须使用List l = new ArrayList(asList(...))以获得不引发OperationNotSupported异常的对象。里斯科夫替代原理有人吗?
飞溅

4
@Splash:removeclear是中的可选操作List,因此asList(...)也遵循合同。OP没有地方说他以后需要添加更多元素,该示例只是一个List需要用三个元素初始化的示例。
ChristofferHammarström,2012年

870

简单的答案

Java 9或更高版本中,List.of()添加之后:

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

Java 10或更高版本中,可以使用var关键字来缩短此时间。

var strings = List.of("foo", "bar", "baz");

这将为您提供一成不变的 List,因此无法更改。
在大多数情况下,这是您想要的。


Java 8或更早版本:

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

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


您可以Arrays.asList使用静态导入来缩短:

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

静态导入:

import static java.util.Arrays.asList;  

任何现代IDE都会建议并自动为您执行的操作。
例如,在IntelliJ IDEA中,按Alt+Enter并选择Static import method...


但是,我不建议将该List.of方法缩短为of,因为这会造成混淆。
List.of已经足够短,而且阅读效果很好。


使用Streams

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

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

您可以串联Stream

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

或者,您可以从Stream转到List

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

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

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


如果您确实需要java.util.ArrayList

(您可能没有。)
引用JEP 269(重点是我的话):

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


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

ArrayList<String> strings = new ArrayList<>(List.of("foo", "bar"));
strings.add("baz");

或在Java 8或更早版本中:

ArrayList<String> strings = new ArrayList<>(asList("foo", "bar"));
strings.add("baz");

或使用Stream

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

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

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


程序接口,而不是实现

您说过已ArrayList在代码中将列表声明为,但仅当使用ArrayList的不是in的某个成员时才应这样做List

您最有可能不这样做。

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

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

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

// 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 .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
}

另一个示例将始终将变量声明InputStreamFileInputStreama BufferedInputStream,即使它通常是a 或a ,因为有一天您或其他人将想要使用其他类型的InputStream


3
@jollyroger:Arrays.asList是静态方法。参见docs.oracle.com/javase/1.5.0/docs/guide/language/…–
ChristofferHammarström

2
@ChristofferHammarström在这种情况下,我的新手头脑告诉我,静态导入与全局变量和与此类用法相关的风险非常相似。这个假设是正确的吗,也是上述类似答案获得更多投票的原因吗?
jollyroger

2
我认为您在谈论的上述答案是一年前做出的。不,全局变量的问题在于它们是可变的。它们与静态导入无关。
ChristofferHammarström,2013年

2
如果您不希望静态导入,则还可以定义静态asList方法的完整路径,如下所示:List <String> strings = java.util.Arrays.asList(“”,“”);
Geert Weening

2
或者您可以使用import java.util.Arrays; 和Arrays.asList(“”,“”); 您不必使用静态导入。您不必使用完整路径。静态方法不在乎导入。如果您使用实例来查找它们,它们将变得很烦。
candied_orange 2014年

111

如果您需要尺寸1的简单清单:

List<String> strings = new ArrayList<String>(Collections.singletonList("A"));

如果您需要几个对象的列表:

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

57

使用番石榴,您可以编写:

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

在Guava中,还有其他有用的静态构造函数。您可以在这里阅读有关它们的信息


1
我很确定您可以使用以下方法来做到这一点,java.util.Arrays例如List<String> names = Arrays.asList("Beckah", "Sam", "Michael");
beckah 2015年

2
@beckah方法Arrays.asLists创建类型为List的对象,而问题是关于创建的ArrayList
帕维尔Adamski的


34

集合文字没有将其纳入Java 8,但是可以使用Stream API在很长的一行中初始化列表:

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

如果您需要确保自己ListArrayList

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

34

及以上,如JEP 269:集合的便利工厂方法中所建议,可以使用现在带有-的集合文字来实现

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

Set<String> set = Set.of("A", "B", "C");

同样的方法也适用于Map-

Map<String, String> map = Map.of("k1", "v1", "k2", "v2", "k3", "v3")

这类似于@coobird所说的Collection Literals 建议。JEP中也进一步阐明了-


备择方案

语言更改已被考虑多次,但被拒绝:

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

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

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

语言建议比该消息中概述的基于图书馆的建议优先放置

相关:Java 9中用于集合的重载便利工厂方法的重点是什么?


31
import com.google.common.collect.ImmutableList;

....

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

4
我不想添加新的依赖项只是为了做到这一点。
Macarse

6
等同于Collections.unmodifiableList(Arrays.asList("Buenos Aires", "Córdoba", "La Plata")),它unmodifiableList(asList("Buenos Aires", "Córdoba", "La Plata"))与静态导入一起使用。您不需要Google收藏夹。
ChristofferHammarström,2010年

9
不,不一样。当unmodifiableList伪装成普通列表时,由于ImmutableList在结果类型中记录了其不变性。
大卫·皮埃尔

2
Google集合提供了可变数组列表,而不是一成不变的列表:List <String> = Lists.newArrayList(“ Buenos Aires”,“Córdoba”,“ La Plata”);
L. Holanda 2012年

3
您将把它传递ImmutableList给采用的其他方法,List然后无论如何都会丢失该文档。
ChristofferHammarström2014年

23

您可以创建一个工厂方法:

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

但这并不比您的第一个重构好多少。

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

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

1
回顾一下原始文章,它要求一行初始化数组,而不是另外7行。
L. Holanda 2012年

7
@LeoHolanda:我同意为每个小事情创建工厂方法太多了。但是根据具体情况以及该方法将要使用的次数,创建它可能是有意义的。创建额外的抽象层意味着通过创建更有意义的方法来捕获设计者的意图,从而消除复杂性。
Jordão酒店


8

关于此的最紧凑的方法是:

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

8

只需使用以下代码,如下所示。

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

2
@bsd您可以在输入任何方法之前使用此方法声明列表。因此,在定义类变量时,无需调用方法即可将内容添加到列表中。
melwil 2014年

2
尽量避免双括号初始化。参见:stackoverflow.com/a/924326/760393

8

使用Eclipse Collections,您可以编写以下内容:

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

您还可以更详细地说明类型以及它们是Mutable还是Immutable。

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

您也可以对Sets和Bags进行同样的操作:

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

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


7

这是另一种方式:

List<String> values = Stream.of("One", "Two").collect(Collectors.toList());

7

(应该是评论,但时间太长,因此需要重新回复)。正如其他人所提到的,该Arrays.asList方法是固定大小的,但这并不是唯一的问题。它也不能很好地处理继承。例如,假设您具有以下条件:

class A{}
class B extends A{}

public List<A> getAList(){
    return Arrays.asList(new B());
}

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

new ArrayList<A>(Arrays.<A>asList(b1, b2, b3))

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


6

您可以使用以下语句:

代码段:

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

List<String> names = Arrays.asList(arr);

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

5

就像汤姆说的

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

但是由于您抱怨想要一个ArrayList,因此首先应该知道ArrayList是List的子类,您可以简单地添加以下行:

ArrayList<String> myPlaces = new ArrayList(places);

虽然,这可能会让您抱怨“性能”。

在这种情况下,这对我来说没有意义,为什么,由于您的列表是预定义的,因此未定义为数组(因为在初始化时知道​​大小)。如果这是您的选择:

String[] places = {"Buenos Aires", "Córdoba", "La Plata"};

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

ArrayList<String> myPlaces = new ArrayList(Arrays.asList(places));

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

enum Places {BUENOS_AIRES, CORDOBA, LA_PLATA}

会成为:

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;
    }
}

枚举有一个静态values方法,该方法按声明顺序返回包含枚举的所有值的数组,例如:

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

在这种情况下,我猜您不需要ArrayList。

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


5

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

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

如果需要,可以轻松地使用它来创建可变列表:

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

类似的方法可用于SetMap


1
您最好明确地说出“不可变列表”,然后显示可变列表的另一个示例,因为这样做可以清楚地说明何时使用哪个列表。
cherit



4

您可以StickyListCactoos使用:

List<String> names = new StickyList<>(
  "Scott Fitzgerald", "Fyodor Dostoyevsky"
);


2

在Java中,您无法执行

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

如前所述,您需要进行双括号初始化:

List<String> places = new ArrayList<String>() {{ add("x"); add("y"); }};

但这可能会迫使您添加注释@SuppressWarnings("serial")或生成令人讨厌的串行UUID。同样,大多数代码格式化程序会将其展开为多个语句/行。

或者你可以做

List<String> places = Arrays.asList(new String[] {"x", "y" });

但随后您可能想要做一个@SuppressWarnings("unchecked")

同样根据javadoc,您应该能够做到这一点:

List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");

但是我无法使其与JDK 1.6一起编译。


5
错误!你可以做第一行,那是正确的答案顺便说一句
波西米亚语

1
Collections.singletonList(messageBody)

如果您需要一份物品清单!

集合来自java.util包。


1

最好的方法是:

package main_package;

import java.util.ArrayList;


public class Stackkkk {
    public static void main(String[] args) {
        ArrayList<Object> list = new ArrayList<Object>();
        add(list, "1", "2", "3", "4", "5", "6");
        System.out.println("I added " + list.size() + " element in one line");
    }

    public static void add(ArrayList<Object> list,Object...objects){
        for(Object object:objects)
            list.add(object);
    }
}

只需创建一个可以包含任意多个元素的函数,然后调用它即可将它们添加到一行中。


1
如果您遇到了所有麻烦,则最好将其设置为模板方法,而不是使用plain方法Object
罗伯特·

1

这是AbacusUtil的代码

// ArrayList
List<String> list = N.asList("Buenos Aires", "Córdoba", "La Plata");
// HashSet
Set<String> set = N.asSet("Buenos Aires", "Córdoba", "La Plata");
// HashMap
Map<String, Integer> map = N.asMap("Buenos Aires", 1, "Córdoba", 2, "La Plata", 3);

// Or for Immutable List/Set/Map
ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");
ImmutableSet.of("Buenos Aires", "Córdoba", "La Plata");
ImmutableSet.of("Buenos Aires", 1, "Córdoba", 2, "La Plata", 3);

// The most efficient way, which is similar with Arrays.asList(...) in JDK. 
// but returns a flexible-size list backed by the specified array.
List<String> set = Array.asList("Buenos Aires", "Córdoba", "La Plata");

声明:我是AbacusUtil的开发人员。



0

为什么不做一个简单的实用函数呢?

static <A> ArrayList<A> ll(A... a) {
  ArrayList l = new ArrayList(a.length);
  for (A x : a) l.add(x);
  return l;
}

ll”代表“文字列表”。

ArrayList<String> places = ll("Buenos Aires", "Córdoba", "La Plata");

0

有趣的是,没有 列出其他重载Stream::collect 方法的单线

ArrayList<String> places = Stream.of( "Buenos Aires", "Córdoba", "La Plata" ).collect( ArrayList::new, ArrayList::add, ArrayList::addAll );

-1

实际上,可以单行执行:

Arrays.asList(new MyClass[] {new MyClass("arg1"), new MyClass("arg2")})

3
请问这对问题有什么影响?该答案已被其他答案多次覆盖。
Mysticial 2013年

这实际上是一个很糟糕的解决方案,因为它会创建一个摘要列表。您将无法再向容器添加任何东西。
阿泰斯(Atais)2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.