Java 16 的 Stream.toList() 和 Stream.collect(Collectors.toList()) 的区别?

2022-09-01 15:27:17

JDK 16 现在直接在实例上包含 toList() 方法。在以前的 Java 版本中,您始终必须使用该方法并提供实例。collectCollector

新方法显然减少了要键入的字符数。这两种方法是否可以互换,还是应该注意存在细微的差异?

var newList = someCollection.stream()
    .map(x -> mapX(x))
    .filter(x -> filterX(x))
    .toList();

// vs.

var oldList = someCollection.stream()
    .map(x -> mapX(x))
    .filter(x -> filterX(x))
    .collect(Collectors.toList());

(这个问题类似于Will Stream.toList()的性能优于Collectors.toList(),但关注的是行为,而不仅仅是性能。


答案 1

一个区别是,它提供了一个不可变的实现(无法添加到或排序的类型),类似于 由 提供的可变(可以更改和排序)的实现,并且与 提供的可变(可以更改和排序)相反。Stream.toList()ListImmutableCollections.ListNList.of()ArrayListStream.collect(Collectors.toList())

演示:

import java.util.stream.Stream;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> list = Stream.of("Hello").toList();
        System.out.println(list);
        list.add("Hi");
    }
}

输出:

[Hello]
Exception in thread "main" java.lang.UnsupportedOperationException
    at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)
    at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:147)
    at Main.main(Main.java:8)

请查看此文章了解更多详情。

更新:

有趣的是,成功返回包含 s 的列表。Stream.toList()null

import java.util.stream.Stream;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Object> list = Stream.of(null, null).toList();
        System.out.println(list);
    }
}

输出:

[null, null]

另一方面,投掷 .List.of(null, null)NullPointerException

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Object> list = List.of(null, null);
    }
}

输出:

Exception in thread "main" java.lang.NullPointerException
    at java.base/java.util.Objects.requireNonNull(Objects.java:208)
    at java.base/java.util.ImmutableCollections$List12.<init>(ImmutableCollections.java:453)
    at java.base/java.util.List.of(List.java:827)
    at Main.main(Main.java:5)

注意:我使用 openjdk-16-ea+34_osx-x64 来编译和执行 Java SE 16 代码。

有用的资源:

  1. JDK 错误 #JDK-8180352
  2. 使用单个空参数调用 Java varargs 方法?

答案 2

下面是一个小表,总结了 和 之间的区别:Stream.collect(Collectors.toList())Stream.collect(Collectors.toUnmodifiableList())Stream.toList()

  • collect(toList()): 保证不可修改性 - ;允许空值 -
  • collect(toUnmodifiableList()):保证不可修改性 - 是的;允许空值 -
  • toList():保证不可修改性 - 是的;允许空值 -

推荐