【问题标题】:Initialization of an ArrayList in one line在一行中初始化 ArrayList
【发布时间】:2010-11-03 13:18:00
【问题描述】:

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

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

有没有更好的方法来做到这一点?

【问题讨论】:

  • 如果这是用于单元测试的,请尝试 groovy。您可以在测试 java 代码时在其中编写测试代码,并使用 ArrasyList&lt;String&gt; places = ["Buenos Aires", "Córdoba", "La Plata"]
  • 在 Java SE 7 中,您可以用一组空的类型参数 () 替换构造函数的参数化类型: Map> myMap = new HashMap( );
  • 使用双支撑初始化 :)
  • Stream.of("val1", "val2").collect(Collectors.toList()); //创建ArrayList,Java8解决方案。

标签: java collections arraylist initialization


【解决方案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"));

【讨论】:

  • 是的,我的班级有一个私有的 ArrayList
  • @Marcase:你能不能改变你的类来使用 List 而不是 ArrayList?
  • 根据我的回答,如果您不使用特定于 ArrayList 的方法,最好将声明更改为 List。指定接口,而不是实现。
  • @Christoffer Hammarström:如果他将声明更改为 List 并使用 List places = Arrays.asList(...); 他将无法使用 places.add("blabla")
  • 要明确一点,asList(...) 返回一个固定大小的List,这会在removeclear 等变异操作上崩溃,List 合约声称支持这些操作。即使您将声明保留为List,您仍然需要使用List l = new ArrayList(asList(...)) 才能获得一个不会引发 OperationNotSupported 异常的对象。 Liskov 替换原则有人吗?
【解决方案2】:

实际上,初始化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 proposal 被接受,那就太好了(它计划在 Java 7 中引入,但也不太可能成为 Java 8 的一部分。):

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

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

【讨论】:

【解决方案3】:

简单的答案

Java 10 或更高版本:

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

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

Java 9

如果您使用的是 Java 9,则不能使用 var 关键字:

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

Java 8 或更早版本:

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

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

* 实现细节:它是java.util.Arrays内部的一个私有嵌套类,命名为ArrayList
这是与java.util.ArrayList 不同的类,尽管它们的简单名称相同。

静态导入

您可以通过静态导入使 Java 8 Arrays.asList 更短:

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

任何现代 IDE* 都会建议并为您执行此操作。

我不建议将List.of 方法静态导入为of,因为它会造成混淆。

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

使用Streams

为什么一定要List
对于 Java 8 或更高版本,您可以使用更灵活的 Stream

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

您可以连接Streams:

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

或者您可以从Stream 转到List

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

如果您特别需要java.util.ArrayList*

如果您想两者预填充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");

或使用Stream:

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

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

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

*您可能不需要专门的ArrayList。引用JEP 269:

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

(强调我的)

编程到接口,而不是实现

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

你最有可能不做的事情。

通常你应该通过你将要使用的最通用的接口(例如IterableCollectionList)来声明变量,并使用特定的实现来初始化它们(例如ArrayList、@ 987654365@ 或 Arrays.asList())。

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

例如,如果您将 ArrayList 传递给 void 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 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

【讨论】:

    【解决方案4】:

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

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

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

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

    【讨论】:

      【解决方案5】:

      Guava 你可以写:

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

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

      【讨论】:

      • 我很确定您只需使用 java.util.Arrays 就可以做到这一点,例如 List&lt;String&gt; names = Arrays.asList("Beckah", "Sam", "Michael");
      • @beckah 方法 Arrays.asLists 创建 List 类型的对象,而问题是关于创建 ArrayList
      • @beckah Arrays.asList 创建一个无法修改的列表。如果列表需要修改,Lists.newArrayList 可以工作,Arrays.asList 不行。
      【解决方案6】:

      对于 及更高版本,正如JEP 269: Convenience Factory Methods for Collections 中所建议的那样,现在可以使用 collection literals 来实现 -

      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 proposal。 JEP 中也进一步澄清了 -


      替代品

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

      Project Coin Proposal, 29 March 2009

      Project Coin Proposal, 30 March 2009

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

      语言 提案被搁置,而不是基于图书馆的提案,因为 总结在此message.

      相关:What is the point of overloaded Convenience Factory Methods for Collections in Java 9

      【讨论】:

        【解决方案7】:

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

        【讨论】:

          【解决方案8】:
          import com.google.common.collect.ImmutableList;
          
          ....
          
          List<String> places = ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");
          

          【讨论】:

          • 我不想为此添加新的依赖项。
          • 这与Collections.unmodifiableList(Arrays.asList("Buenos Aires", "Córdoba", "La Plata")) 相同,在静态导入时变为unmodifiableList(asList("Buenos Aires", "Córdoba", "La Plata"))。你不需要谷歌收藏。
          • 不,不一样。因为当 unmodifiableList 将其伪装成普通列表时,ImmutableList 会在结果类型中记录其不变性。
          • 除了不可变数组之外,google 集合还提供可变数组列表: List = Lists.newArrayList("Buenos Aires", "Córdoba", "La Plata");
          • 您将把 ImmutableList 传递给采用 List 的其他方法,然后无论如何您都丢失了该文档。
          【解决方案9】:

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

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

          【讨论】:

          • 回看原来的帖子,它是在一行中要求数组初始化,而不是7行。
          • @LeoHolanda:我同意,为每件小事都创建工厂方法太多了。但根据情况,以及该方法将要使用的次数,创建它可能是有意义的。创建额外的抽象层是为了消除复杂性,通过创建更多有意义的方法来捕捉设计者的意图
          • 我认为我们可以将增强的for 替换为Collections.addAll(elements),如here 所述。
          【解决方案10】:

          在 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. Space Efficiency
          2. Immutability
          3. Thread Safe

          查看这篇文章了解更多详情 -> What is the difference between List.of and Arrays.asList?

          【讨论】:

            【解决方案11】:

            最简洁的方法是:

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

            【讨论】:

              【解决方案12】:

              只需使用下面的代码如下。

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

              【讨论】:

                【解决方案13】:

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

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

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

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

                【讨论】:

                  【解决方案14】:

                  这是另一种方式:

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

                  【讨论】:

                    【解决方案15】:

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

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

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

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

                    这可能是最好的方法,尤其是。如果您需要无限列表或需要使用继承。

                    【讨论】:

                      【解决方案16】:

                      您可以使用以下语句:

                      代码片段:

                      String [] arr = {"Sharlock", "Homes", "Watson"};
                      
                      List<String> names = Arrays.asList(arr);
                      

                      【讨论】:

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

                      点赞Tom said

                      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。

                      附: Randyaa demonstrated 另一个使用静态实用方法Collections.addAll 的好方法。

                      【讨论】:

                        【解决方案18】:

                        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 也有类似的方法。

                        【讨论】:

                        • 您明确表示“不可变列表”然后展示了另一个可变列表示例,因为它清楚地说明了何时使用。
                        【解决方案19】:
                        List<String> names = Arrays.asList("2","@2234","21","11");
                        

                        【讨论】:

                          【解决方案20】:

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

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

                          【讨论】:

                            【解决方案21】:

                            你可以从Cactoos使用StickyList

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

                            【讨论】:

                              【解决方案22】:

                              试试这个代码行:

                              Collections.singletonList(provider)
                              

                              【讨论】:

                              • 添加您的答案的简短描述。
                              【解决方案23】:

                              使用 Arrays.asList("Buenos Aires", "Córdoba", "La Plata"); 是正确的。但是任何对Arrays.asList() 的零参数或只有一个参数的调用都可以替换为对Collections.singletonList()Collections.emptyList() 的调用,这将节省一些内存。

                              注意:Collections.singletonList() 返回的列表是不可变的,而Arrays.asList() 返回的列表允许调用 set() 方法。在极少数情况下,这可能会破坏代码。

                              【讨论】:

                                【解决方案24】:

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

                                【讨论】:

                                • 错了!你可以做第一行,这是正确的答案顺便说一句
                                【解决方案25】:
                                Collections.singletonList(messageBody)
                                

                                如果您需要一个项目的列表!

                                Collections 来自 java.util 包。

                                【讨论】:

                                  【解决方案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);
                                      }
                                  }
                                  

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

                                  【讨论】:

                                  • 如果你遇到了所有的麻烦,你不妨把它变成一个模板方法,而不是使用普通的Object
                                  【解决方案27】:

                                  这是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的开发者。

                                  【讨论】:

                                    【解决方案28】:

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

                                    【讨论】:

                                    • 为什么 Arrays.asList() 比使用 add() 方法在一行中创建一个新的 ArrayList 更好?
                                    【解决方案29】:

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

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

                                    【讨论】:

                                    • 您可以使用 Collections.addAll 代替 for 循环。另外,如果您将方法命名为list,则该名称不需要解释:)
                                    【解决方案30】:

                                    有趣的是,没有一个线程与另一个重载 Stream::collect 方法已列出

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

                                    【讨论】:

                                      猜你喜欢
                                      • 2015-06-28
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 2011-05-11
                                      • 2018-03-15
                                      • 1970-01-01
                                      相关资源
                                      最近更新 更多