提问



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


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


有一个更好的方法吗?

最佳参考


实际上,初始化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 Coin的Collection Literals提议被接受(它将在Java 7中引入,但它不可能也是Java 8的一部分,那么本来不错的是。):[130] [131]


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


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

其它参考1


如果你只是将它声明为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"));

其它参考2


简单的答案



在Java 8或更早版本中:


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


这将给你一个List数组支持,所以它不能改变长度。

但你可以打电话List.set,所以它仍然是可变的。





在Java 9中:


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


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





答案较短



使用静态导入可以使Arrays.asList更短:


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


静态导入:


import static java.util.Arrays.asList;  


任何现代IDE都会建议并自动为您做。

例如,在IntelliJ IDEA中按Alt+Enter并选择Static import method...





但是,我不建议缩短Java 9 List.of方法,因为只有of会变得混乱。

List.of已经足够短并且读得很好。





使用Stream s



为什么它必须是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"));


或者你可以从StreamList:


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


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





如果确实特别需要java.util.ArrayList



(你可能不会。)

引用JEP 269(强调我的):[132]



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






如果您想两者预先填充ArrayList 并之后添加(为什么?),请使用


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


或者在Java 9中:


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


或使用Stream:


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


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





编程到接口,而不是实现



你说你已经在你的代码中将列表声明为ArrayList,但是如果你使用ArrayList中某些不在List中的成员,你应该这样做。


你很可能不会这样做。


通常你应该通过你将要使用的最通用的接口声明变量(例如IterableCollectionList),并用特定的实现初始化它们(例如[[]] 105]],LinkedListArrays.asList())。


否则,您将代码限制为特定类型,并且在您希望时更难以进行更改。


例如:


// Iterable if you just need iteration, for (String s : strings):
Iterable<String> strings = new ArrayList<>();   

// Collection if you also need .size() or .stream():
Collection<String> strings = new ArrayList<>(); 

// List if you also need .get(index):
List<String> strings = new ArrayList<>();       

// Don't declare a specific list implementation
// unless you're sure you need it:
ArrayList<String> strings = new ArrayList<>();  // You don't need ArrayList





另一个例子总是声明变量InputStream,即使它通常是FileInputStreamBufferedInputStream,因为有一天你或其他人会想要使用其他类型InputStream InputStream 111]]。

其它参考3


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


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


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


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

其它参考4


用番石榴你可以写:[133]


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


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

其它参考5


集合文字没有进入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));

其它参考6


import com.google.common.collect.ImmutableList;

....

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

其它参考7


您可以创建工厂方法:


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

其它参考8


使用Java 9,如JDK增强提案 - 269中所建议的那样,现在可以使用集合文字来实现 - [135]


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文件中进一步澄清 - [136]





替代



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

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

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

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

  
  语言
  提议被搁置优先于基于图书馆的提案
  在此消息中总结。[140]



关于相同的链接阅读〜> 重载方便工厂方法有什么意义

其它参考9


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


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


要么


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


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



  1. 空间效率

  2. 不变性

  3. 线程安全



有关更多详细信息,请参阅此帖子 - > List.of和Arrays.asList有什么区别? [142] [143] [144]

其它参考10


关于最紧凑的方法是:


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

其它参考11


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


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


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


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的提交者。

其它参考12


只需使用以下代码如下。


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

其它参考13


这是另一种方式:


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

其它参考14


您可以使用以下语句:


代码段:



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

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

其它参考15


(应该是评论,但是太长了,所以新回复)。正如其他人所提到的那样,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))


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

其它参考16


像汤姆说:


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


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


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


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


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


[[43.]]

如果您不关心轻微的性能差异,那么您也可以非常简单地将数组复制到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。


附: Randyaa演示了另一种使用静态实用程序方法Collections.addAll的好方法。 [150]

其它参考17


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

其它参考18


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

其它参考19


你可以使用Cactoos的StickyList:[151]


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

其它参考20


尝试使用此代码行:


Collections.singletonList(provider)

其它参考21


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


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

其它参考22


在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编译它。

其它参考23


Collections.singletonList(messageBody)


如果您需要列出一个项目!


集合来自 java.util 包。

其它参考24


这是AbacusUtil的代码[152]


// 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的开发人员。

其它参考25


对我来说,Arrays.asList()是最好的和最方便的。我总是喜欢这样初始化。
如果您是Java Collections的初学者,那么我希望您参考ArrayList初始化[153]

其它参考26


最好的方法:


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


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

其它参考27


为什么不做一个简单的实用功能呢?


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

其它参考28


实际上,它可以在一行中完成:


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

其它参考29


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


这是Arrays.asList的实现,所以你可以选择


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