Java 使用一行代码初始化列表 List

评论 0 浏览 0 2018-08-16

1. 概述

在这个快速教程中,我们将研究如何使用单行代码初始化列表

2. 从数组创建

我们可以从数组创建一个列表。多亏了数组文字,我们可以在一行中初始化它们:

List<String> list = Arrays.asList(new String[]{"foo", "bar"});

我们可以信任 varargs 机制来处理数组创建。这样,我们就可以编写更简洁易读的代码:

@Test
public void givenArraysAsList_thenInitialiseList() {
    List<String> list = Arrays.asList("foo", "bar");

    assertTrue(list.contains("foo"));
}

此代码的结果实例实现了 List 接口,但它不是 java.util.ArrayListLinkedList 相反,它是一个由原始数组支持的列表,它有两个含义,我们将在本节的其余部分中讨论。

尽管该类的名称恰好是 ArrayList,但它位于 java.util.Arrays 包中。

2.1.固定大小

Arrays.asList 的结果实例将具有固定大小:

@Test(expected = UnsupportedOperationException.class)
public void givenArraysAsList_whenAdd_thenUnsupportedException() {
    List<String> list = Arrays.asList("foo", "bar");

    list.add("baz");
}

2.2.共享引用

原始数组和列表共享对对象的相同引用:

@Test
public void givenArraysAsList_whenCreated_thenShareReference(){
    String[] array = {"foo", "bar"};
    List<String> list = Arrays.asList(array);
    array[0] = "baz";
 
    assertEquals("baz", list.get(0));
}

3. 从流创建 (Java 8)

我们可以轻松地将转换为任何类型的集合。

因此,通过 Streams 的工厂方法,我们可以在一行中创建和初始化列表:

@Test
public void givenStream_thenInitializeList(){
    List<String> list = Stream.of("foo", "bar")
      .collect(Collectors.toList());
		
    assertTrue(list.contains("foo"));
}

这里我们应该注意,Collectors.toList() 并不能保证返回的 List 的准确实现。

关于返回实例的可变性、可序列化性或线程安全性没有一般约定。因此,我们的代码不应依赖于任何这些属性。

一些消息来源强调,Stream.of(...).collect(...) 可能比 Arrays.asList() 具有更大的内存和性能占用量。但在几乎所有情况下,这种微观优化几乎没有什么区别。

4.工厂方法(Java 9)

JDK 9 引入了几种方便的集合工厂方法:

List<String> list = List.of("foo", "bar", "baz");
Set<String> set = Set.of("foo", "bar", "baz");

一个重要的细节是返回的实例是不可变的。除此之外,工厂方法在空间效率和线程安全性方面还有一些优势。

本文对此主题进行了更多探讨。

5. 双括号初始化

在几个地方,我们可以找到一种称为双括号初始化的方法,如下所示:

@Test
public void givenAnonymousInnerClass_thenInitialiseList() {
    List<String> cities = new ArrayList() {{
        add("New York");
        add("Rio");
        add("Tokyo");
    }};

    assertTrue(cities.contains("New York"));
}

“双括号初始化”这个名字很有误导性。虽然语法看起来紧凑而优雅,但它危险地隐藏了幕后发生的事情。

Java 中实际上没有双括号语法元素;这是两个故意以这种方式格式化的块。

使用外部大括号,我们声明一个匿名内部类,它将成为 ArrayList 的子类。我们可以在这些大括号内声明子类的详细信息。

像往常一样,我们可以使用实例初始化块,这就是内部大括号对的来源。

这种语法的简洁性很有吸引力。然而,它被认为是一种反模式。

要了解有关双括号初始化的更多信息,请查看我们的文章此处

六,结论

现代 Java 提供了多种选项来在一行中创建集合我们选择的方法几乎完全取决于个人喜好,而不是技术推理。

一个重要的结论是,尽管它看起来很优雅,匿名内部类初始化的反模式(又名双大括号)有许多负面影响。

与往常一样,代码可以在 GitHub 上获取。

最后更新2023-11-15
0 个评论
标签