关于Java:在一行中初始化ArrayList

Initialization of an ArrayList in one line

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

1
2
3
4
ArrayList<String> places = new ArrayList<String>();
places.add("Buenos Aires");
places.add("Córdoba");
places.add("La Plata");

然后我重构代码如下:

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

有更好的方法吗?


如果你只是把它声明为一个List,那就简单了——它必须是一个数组列表吗?

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

或者如果只有一个元素:

1
List<String> places = Collections.singletonList("Buenos Aires");

这意味着places是不变的(试图改变它会导致UnsupportedOperationException异常被抛出)。

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

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


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

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

关键是,要引用该List实例,需要输入大量的类型。

有一些替代方法,例如使用实例初始值设定项生成匿名内部类(也称为"双括号初始化"):

1
2
3
4
5
ArrayList<String> list = new ArrayList<String>() {{
    add("A");
    add("B");
    add("C");
}};

但是,我不太喜欢这个方法,因为您最终得到的是一个ArrayList的子类,它有一个实例初始值设定项,而这个类是为创建一个对象而创建的——在我看来这有点过分了。

如果项目硬币的集合文字建议被接受(它是在Java 7中引入的,但是它也不太可能是Java 8的一部分),那就好了。

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

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


简单的答案

在Java 10或更高版本中:

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

在Java 9或更高版本中:

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

这将给您一个不变的List,因此它不能更改。在大多数情况下,你需要的是预先填充它。

Java 8或更早:

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

这将给您一个由数组支持的List,因此它不能更改长度。但是你可以叫List.set,所以它仍然是可变的。

通过静态导入,可以使Arrays.asList更短:

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

静态导入:

1
import static java.util.Arrays.asList;

任何现代的IDE都会建议并自动为您做这些。例如,在intellij idea中,您按Alt+Enter并选择Static import method...

但是,我不建议缩短Java 9 EDCOX1 6的方法,因为只有EDCX1 7的内容变得混乱。List.of已经足够短,读起来也不错。

使用Streams

为什么必须是一个List?使用Java 8或更高版本后,可以使用更灵活的EDCOX1×9表示:

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

您可以连接Streams:

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

或者你可以从一个Stream转到一个List

1
2
3
import static java.util.stream.Collectors.toList;

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

但最好使用Stream,而不收集到List

如果你真的需要一台java.util.ArrayList

(你可能没有。)引用jep 269(强调我的):

There is a small set of use cases for initializing a mutable collection instance with a predefined set of values. It's usually preferable to have those predefined values be in an immutable collection, and then to initialize the mutable collection via a copy constructor.

如果你想预先填充一个ArrayList,然后再添加(为什么?)使用

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

或在Java 8或更早:

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

或使用Stream

1
2
3
4
5
import static java.util.stream.Collectors.toCollection;

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

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

程序到接口,而不是实现

你说你已经在代码中声明了这个列表为ArrayList,但是只有当你使用的ArrayList的某个成员不在List中时,你才应该这样做。

你很可能不会这么做。

通常,您只需通过要使用的最通用的接口(如IterableCollectionList)声明变量,并使用特定的实现(如ArrayListLinkedListArrays.asList()初始化变量。

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

例如,如果您将一个ArrayList传递给一个void method(...)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 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
}

另一个例子是声明变量InputStream,即使它通常是FileInputStreamBufferedInputStream,因为很快你或其他人就会想要使用其他类型的InputStream


如果您需要1号的简单列表:

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

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

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


有了番石榴,你可以写:

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

在guava中还有其他有用的静态构造函数。你可以在这里读到它们。


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

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

如果您需要确保您的ListArrayList

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

1
2
3
4
5
import com.google.common.collect.ImmutableList;

....

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


如JDK增强方案-269中建议的那样,使用Java 9可以通过使用集合文本来实现-

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

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

同样,类似的方法也适用于Map。-

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

这类似于@coobird提出的收集文字建议。在jep文件中进一步澄清-

选择

Language changes have been considered several times, and rejected:

Project Coin Proposal, 29 March 2009

Project Coin Proposal, 30 March 2009

JEP 186 discussion on lambda-dev, January-March 2014

The language
proposals were set aside in preference to a library-based proposal as
summarized in this message.

Java9中过载的便利工厂方法的要点是什么?


可以创建工厂方法:

1
2
3
4
5
6
7
8
9
10
11
12
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");

但这并不比第一次重构好多少。

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

1
2
3
4
5
6
7
public static <T> ArrayList<T> createArrayList(T ... elements) {
  ArrayList<T> list = new ArrayList<T>();
  for (T element : elements) {
    list.add(element);
  }
  return list;
}


在Java 9中,我们可以很容易地在一行中初始化EDCOX1×3条:

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

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

Java 9的这种新方法比以前的有很多优点:

  • 空间效率
  • 不变性
  • 线程安全
  • 请参阅本文了解更多详细信息->list.of和arrays.aslist之间的区别是什么?


    另一种方法是:

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

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

    1
    2
    3
    4
    5
    List<String> list = new ArrayList<String>() {{
                add("A");
                add("B");
                add("C");
    }};


    使用Eclipse集合(以前称为GS集合),可以编写以下内容:

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

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

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

    您也可以对套装和行李进行同样的操作:

    1
    2
    3
    4
    5
    6
    7
    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集合的提交者。


    最紧凑的方法是:

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


    您可以使用以下语句:

    代码片段:

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

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


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

    1
    2
    3
    4
    5
    6
    class A{}
    class B extends A{}

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

    由于List不是List的子类,即使可以向List对象添加类型B的对象,也会导致编译器错误。为了解决这个问题,你需要做如下的事情:

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

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


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

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

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

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

    类似的方法也适用于SetMap


    就像汤姆所说:

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

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

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

    不过,这可能会让你抱怨"表现"。

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

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

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

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

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

    1
    enum Places {BUENOS_AIRES, CORDOBA, LA_PLATA}

    将成为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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方法,该方法返回一个数组,该数组按声明的顺序包含枚举的所有值,例如:

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

    那样的话,我想你不需要你的阵列列表。

    P.S.Randya演示了另一种使用静态实用工具方法collections.addall的好方法。


    1
    List<String> names = Arrays.asList("2","@2234","21","11");


    您可以使用cactoos的StickyList

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

    尝试使用此代码行:

    1
    Collections.singletonList(provider)


    是的,在数组的帮助下,您可以在一行中初始化数组列表,

    1
    List<String> strlist= Arrays.asList("aaa","bbb","ccc");

    在爪哇,你做不到

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

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

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

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

    或者你也可以

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

    但是你可能想做一个@SuppressWarnings("unchecked")

    根据JavaDoc,您应该能够做到:

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

    但是我不能用JDK1.6编译它。


    1
    Collections.singletonList(messageBody)

    如果你需要一个物品清单!

    集合来自java.util包。


    最好的方法是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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);
        }
    }

    只需创建一个可以拥有任意多个元素的函数,并调用它将它们添加到一行中。


    这是AbacusUtil的代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 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的开发者。


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

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

    "EDOCX1"〔0〕代表"字面清单"。

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

    对于我来说,array.aslist()是最好和方便的。我总是喜欢这样初始化。如果您是Java集合的初学者,那么我希望您参考ARARYLIST初始化。


    实际上,可以用一行来完成:

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


    1
    2
    3
    public static <T> List<T> asList(T... a) {
        return new ArrayList<T>(a);
    }

    这是Arrays.asList的实现,因此您可以

    1
    ArrayList<String> arr = (ArrayList<String>) Arrays.asList("1","2");