14

你如何创建一个UnmodifiableList/Set/Map Collectors.toList/toSet/toMap,因为toList(等)文档为:

不保证返回的 List 的类型、可变性、可序列化性或线程安全性

java-10 之前,您必须提供Functionwith Collectors.collectingAndThen,例如:

 List<Integer> result = Arrays.asList(1, 2, 3, 4)
            .stream()
            .collect(Collectors.collectingAndThen(
                    Collectors.toList(),
                    x -> Collections.unmodifiableList(x)));
4

4 回答 4

13

使用 Java 10,这更容易并且更具可读性:

List<Integer> result = Arrays.asList(1, 2, 3, 4)
            .stream()
            .collect(Collectors.toUnmodifiableList());

在内部,它与 相同,但返回一个在 Java 9 中添加Collectors.collectingAndThen的不可修改的实例。List

于 2018-03-05T09:06:29.647 回答
8

此外,要清除两个(collectingAndThenvs toUnmodifiableList)实现之间的记录差异:

Collectors.toUnmodifiableList返回一个不允许空值的收集器,NullPointerException如果它有一个null值将抛出。

static void additionsToCollector() {
    // this works fine unless you try and operate on the null element
    var previous = Stream.of(1, 2, 3, 4, null)
            .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));

    // next up ready to face an NPE
    var current = Stream.of(1, 2, 3, 4, null).collect(Collectors.toUnmodifiableList());
}

此外,这是因为前者构造了一个实例,Collections.UnmodifiableRandomAccessList而后者构造了一个实例,该实例添加到使用静态工厂方法ImmutableCollections.ListN带到表中的属性列表中。

于 2018-03-05T10:10:35.553 回答
3

Stream#toList

Java 16Stream在接口上增加了一个方法: toList(). 引用 Javadoc:

返回List是不可修改的;对任何 mutator 方法的调用总是会导致UnsupportedOperationException被抛出。

不仅比 更方便Collectors,这种方法还有一些好处,比如在并行流上的性能更好。

特别是使用 parallel() - 因为它避免了结果复制。Benchmark 是对 Long 的 100K elem 流的一些简单操作。

Java Mission Control toList 性能

如需进一步阅读,请访问: http: //marxsoftware.blogspot.com/2020/12/jdk16-stream-to-list.html

在简历中,链接状态是这样的。

问题:进入一个人的代码库并使用 stream.toList() 作为 stream.collect(Collectors.toList()) 的替代品可能很诱人,但如果代码具有直接或间接依赖于返回 ArrayList 的 stream.collect(Collectors.toList()) 的实现。stream.collect(Collectors.toList()) 和 stream.toList() 返回的 List 之间的一些关键区别将在本文的其余部分中详细说明。

Collectors.toList() 的基于 Javadoc 的文档指出(添加了重点),“返回一个将输入元素累积到新列表中的收集器。不保证列表的类型、可变性、可序列化性或线程安全性返回...” 虽然无法保证 Collectors.toList() 提供的 List 上的“类型、可变性、可序列化性或线程安全性”,但预计有些人可能已经意识到它当前是一个 ArrayList 并已使用它的方式取决于 ArrayList 的特性

我的理解是 Stream.toList() 它将导致一个不可变的列表。

Stream.toList() 提供了一个不可变的 List 实现(类型 ImmutableCollections.ListN,无法添加或排序),类似于 List.of() 提供的实现,与提供的可变(可以更改和排序)ArrayList 形成对比通过 Stream.collect(Collectors.toList())。任何现有代码取决于对 Stream.collect(Collectors.toList()) 返回的 ArrayList 进行变异的能力,将无法与 Stream.toList() 一起使用,并且将引发 UnsupportedOperationException。

虽然 Stream.collect(Collectors.toList()) 和 Stream.toList() 返回的 List 的实现性质非常不同,但它们仍然实现 List 接口,因此在使用 List.equals(Object )

而且这个方法将允许空值,所以从 Java 16 开始,我们将有一个

mutable/null-friendly----->Collectors.toList()
immutable/null-friendly--->Stream.toList()
immutable/null-hostile---->Collectors.toUnmodifiableList() //Naughty 

推特对话 这很棒。

于 2021-01-19T11:34:47.237 回答
0

List/Set/Map.copyOf

您询问:

你如何创建一个不可修改的列表/集合/地图

从 Java 10 开始,只需将现有的 list/set/map 传递给:

这些静态方法分别返回unmodifiableListunmodifiableSetunmodifiableMap。阅读这些链接的 Javadoc 页面上的详细信息。

  • 不允许有空值。
  • 如果传递的集合已经不可修改,则简单地返回传递的集合,没有进一步的工作,没有新的集合。

注意:如果使用其他答案Stream#toList中描述的Java 16+中的便捷方法,则此解决方案没有意义,无需调用。的结果已经无法修改。List.copyOftoList

于 2021-08-19T22:03:59.750 回答