8

查看 的实现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 源代码中实现有什么好的理由吗?

4

1 回答 1

18

toArray方法可能会被实现为返回一个数组,该数组随后会发生变异,这将有效地使返回的列表不是不可变的。这就是为什么通过创建新副本来ArrayList完成显式副本的原因。

它本质上是一个防御副本。

在审查此 API时也讨论了这一点,Stuart Marks 写道:

正如所写,默认实现确实执行了明显冗余的副本,但我们不能保证 toArray() 实际上返回一个新创建的数组。因此,我们使用 Arrays.asList 包装它,然后使用 ArrayList 构造函数复制它。这是不幸的,但有必要避免有人可能持有对 List 的内部数组的引用,从而允许修改应该是不可修改的 List。

于 2021-04-04T21:34:10.973 回答