有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

一行中ArrayList的java初始化

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

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

有更好的方法吗


共 (6) 个答案

  1. # 1 楼答案

    JEP 269: Convenience Factory Methods for Collections中所建议的及以上版本,这可以通过使用集合文本实现,现在使用-

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

    类似的方法也适用于{}

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

    这类似于@coobird所说的Collection Literals proposal。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.

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

  2. # 2 楼答案

    如果您只是将它声明为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"));
    
  3. # 3 楼答案

    简单的答案

    Java 10或更高版本:

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

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

    爪哇9

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

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

    Java 8或更早版本:

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

    这将为您提供一个由数组支持的List*,因此它不能更改长度
    但是你可以调用^{,所以它仍然是可变的

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

    静态导入

    您可以通过静态导入使Java 8Arrays.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

    ^{10}pr$

    但是再次强调,最好直接使用Stream,而不是将其收集到List

    *您可能不需要特定的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,但只有当您使用的是ArrayList中不在List中的某个成员时,才应该这样做

    而你很可能不会这么做

    通常,您应该通过将要使用的最通用的接口(例如IterableCollectionList)声明变量,并使用特定的实现(例如ArrayListLinkedListArrays.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. # 4 楼答案

    实际上,初始化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,而且,如果可能的话,它还不可用

  5. # 5 楼答案

    使用Guava可以编写:

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

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

  6. # 6 楼答案

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

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

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

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