问题描述
查看 Stream#toList
的实现,我只是注意到它看起来过于复杂和不理想。
就像上面的 javadoc 中提到的那样,大多数 default
实现都没有使用这个 Stream
实现,但是,在我看来,它本来可以是其他的。
来源
/**
* Accumulates the elements of this stream into a {@code List}. The elements in
* the list will be in this stream's encounter order,if one exists. The returned List
* is unmodifiable; calls to any mutator method will always cause
* {@code UnsupportedOperationException} to be thrown. There are no
* guarantees on the implementation type or serializability of the returned List.
*
* <p>The returned instance may be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* Callers should make no assumptions about the identity of the returned instances.
* Identity-sensitive operations on these instances (reference equality ({@code ==}),* identity hash code,and synchronization) are unreliable and should be avoided.
*
* <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
*
* @apiNote If more control over the returned object is required,use
* {@link Collectors#toCollection(supplier)}.
*
* @implSpec The implementation in this interface returns a List produced as if by the following:
* <pre>{@code
* Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())))
* }</pre>
*
* @implNote Most instances of Stream will override this method and provide an implementation
* that is highly optimized compared to the implementation in this interface.
*
* @return a List containing the stream elements
*
* @since 16
*/
@SuppressWarnings("unchecked")
default List<T> toList() {
return (List<T>) Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())));
}
我认为什么会更好
return (List<T>) Collections.unmodifiableList(Arrays.asList(this.toArray()));
甚至
return Arrays.asList(this.toArray()));
IntelliJ 的提议
return (List<T>) List.of(this.toArray());
在 JDK 源代码中实现有什么好的理由吗?
解决方法
toArray
方法可能会被实现以返回一个数组,该数组随后会发生变异,这将有效地使返回的列表不可变。这就是为什么通过创建新的 ArrayList
来完成显式复制的原因。
它本质上是一个防御性副本。
这也在 review of this API 期间讨论过,Stuart Marks 写道:
正如所写的那样,默认实现确实执行了明显的冗余副本,但我们不能保证 toArray() 实际上返回一个新创建的数组。因此,我们使用 Arrays.asList 包装它,然后使用 ArrayList 构造函数复制它。这是不幸的,但对于避免有人持有对 List 的内部数组的引用的情况是必要的,从而允许修改本应不可修改的 List。