为什么 Collectors.toList() 不能保证可变性

问题描述 投票:0回答:1

toList() 的实现明确返回一个 ArrayList,它确实保证了可变性:

public static <T>
Collector<T, ?, List<T>> toList() {
    return new CollectorImpl<>(ArrayList::new, List::add,
                               (left, right) -> { left.addAll(right); return left; },
                               CH_ID);
}

但是 toList 的 JavaDoc 是这样写的:

/**
 * Returns a {@code Collector} that accumulates the input elements into a
 * new {@code List}. There are no guarantees on the type, mutability,
 * serializability, or thread-safety of the {@code List} returned; if more
 * control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
 *
 * @param <T> the type of the input elements
 * @return a {@code Collector} which collects all the input elements into a
 * {@code List}, in encounter order
 */

为什么不能保证可变性?我是否遗漏了返回的集合可能不可变的情况?当返回的集合需要可变性时,使用 Collectors.toList() 是否安全?

java collections java-8 java-stream collectors
1个回答
7
投票

因为作者是这么说的

为什么不能保证可变性?

因为

Collectors.toList
方法的设计者选择了这样。

toList()的实现显然返回一个ArrayList

这个事实只是一个实现细节。

该细节仅适用于您研究的一种实现的一个版本。其他版本和其他实现可能会使用

ArrayList
以外的其他内容。

在文档承诺的合同范围内,任何实施都可能发生变化。重要的是该文档所承诺的行为。

引用Javadoc:

返回一个

Collector
,将输入元素累积到一个新的
List
中。不保证返回的
List
的类型、可变性、可序列化性或线程安全性;如果需要对返回的列表进行更多控制,请使用
toCollection(Supplier)

对我来说似乎很清楚。我们已向您承诺,生成的

List
可能是可变的,也可能是不可变的。你被告知不要依赖这两种情况。

可修改

如果您想要一个可变/可修改的

List
,请从收集器生成的列表中创建一个新的。将收集到的列表传递给新列表对象的构造函数。

List< Whatever > list = new ArrayList<>( collectorList ) ;

或者,正如上面的 Javadoc 所建议的,您可以 👉🏽 传递

Supplier
来呈现您选择的列表实现。致电
Collectors.toCollection
。请参阅 Baeldung.com 上教程的第 3.3 节。

例如:

toCollection( ArrayList :: new )
不可修改

如果您想要一个不可变/

不可修改列表,我建议👉🏽致电List.copyOf


List< Whatever > list = List.copyOf( collectorList ) ;
该方法承诺返回:

…一个不可修改的列表,包含给定

Collection

 的元素,按其迭代顺序。

但有一个问题:不允许空值。带有空值的列表的两种选择:


顺便说一句,Java 21 带来了

顺序集合。所以List

更通用的接口是
SequencedCollection

SequencedCollection< Whatever > sequence = List.copyOf( collectorList ) ;
    
© www.soinside.com 2019 - 2024. All rights reserved.