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が行われます。

それは本質的に防御的なコピーです。

これは、Stuart Marks が書いているこの APIのレビュー中にも議論されました。

書かれているように、デフォルトの実装が明らかに冗長なコピーを実行するのは事実ですが、 toArray() が実際に新しく作成された配列を返すとは限りません。したがって、Arrays.asList を使用してラップし、ArrayList コンストラクターを使用してコピーします。これは残念なことですが、誰かが List の内部配列への参照を保持し、変更できないはずの List を変更できる状況を避けるために必要です。

于 2021-04-04T21:34:10.973 に答える