Stream.toList的实现(和文档)如下所示:

Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())))

我想知道为什么由Arrays.asList返回的列表需要复制到新的ArrayList.仅仅退回以下内容还不够吗?

Collections.unmodifiableList(Arrays.asList(this.toArray()))

我想知道,如果我编写一个返回它创建的列表的方法,如果我不费心制作它的防御性副本,会有什么问题吗?

推荐答案

这是有目的的

我想知道为什么Arrays.asList返回的列表需要复制到新的ArrayList.仅仅退回以下内容还不够吗?

我们说的是哪.toArray()个?如果我们讨论的是j.u.Collection中的那个数组,那么您是对的:toArray()方法guarantees的javadoc是一个新分配的数组,因此,不需要进行防御性复制.然而,这并不是这里涉及的toArray()人:我们谈论的是j.u.s.Stream英尺的S .toArray().它的javadoc要短得多:

    /**
     * Returns an array containing the elements of this stream.
     *
     * <p>This is a <a href="package-summary.html#StreamOps">terminal
     * operation</a>.
     *
     * @return an array, whose {@linkplain Class#getComponentType runtime component
     * type} is {@code Object}, containing the elements of this stream
     */

j.u.Collection toArray()不同的是,这个javadoc没有以任何方式说明该数组的性质.因此,显然,Stream中的默认Impl并不假定数组一定是"安全的"("安全"的意思是:以后不会被修改).

我想你是知道的,但我要澄清的是:

Arrays.asList美元几乎总是一个错误.这是一个两全其美的列表:它在您传递给它的数组周围创建了一个光包装.因此,set()可以工作(因为foo[x] = value;是可能的,实际上,它是如何实现的),但是.add()不能(因为您不能改变数组的大小).该列表并不是一成不变的(即,如果将其传递给您的直接控制之外的代码,您需要广泛地记录,或者,制作一个防御性副本),但也不是一个功能齐全的列表.取而代之的是List.of,这使得列表完全不可变--列表可以传递给任何你喜欢的人,而不必担心失go 对完整性的控制.

不过,这并不像你想的那么严重.

请注意,您找到的代码只是默认实现--流的任何特定实现都可以自由地想出更好的方法来实现这一点.几乎您肯定会遇到的每个实现都覆盖了该定义.例如,如果您调用一个arraylist的stream(),那么您将得到这个实现,它来自Streamop,并且与核心库中的所有集合使用的代码路径相同.因此,您最终使用的实际代码是:

    @Override
    public List<P_OUT> toList() {
        return SharedSecrets.getJavaUtilCollectionAccess()
        .listFromTrustedArrayNullsAllowed(this.toArray());
    }

"受信任的数组"在这里指的是传递给它的数组保证不会在您的控制下改变.编译器不可能强制执行这一保证,但是arraylist的(事实上,所有未中断的集合,假设j.u.Collection的javadoc需要这样做!)toArray()生成了新的数组,因此这样做是安全的,而且这样做的效率要高得多(避免了一堆不必要的副本).

Java相关问答推荐

Listview—在Android Java中正确链接项目时出错

Spring Batch 5-不要让它在数据库中自动创建表

流迭代列表<;对象>;上的NoSuchElementException

扩展到弹出窗口宽度的JavaFX文本字段

编译多个.Java文件并运行一个依赖于用户参数的文件

Helidon 4和Http API

将响应转换为带值的键

使用OAuth 2.0资源服务器JWT时的授权(授权)问题

如何在代码中将行呈现在矩形前面?

Kotlin Val是否提供了与Java最终版相同的可见性保证?

Quarkus:运行时出现EnumConstantNotPresentException

从12小时开始的日期模式

嘲笑黄瓜中的对象

在具有Quarkus Panache的PostgreSQL中将JSON数据存储为JSONB时,会将其存储为转义字符串

如何使用Java ZoneID的区域设置?

将基于实例编号的对象列表拆分为新的对象列表

Eureka客户端无法使用用户/通行证注册到Eureka服务器

java 11上出现DateTimeParseException,但java 8上没有

@此处不能应用可为null的批注

如何调查进程列表中不可见的活跃 MySQL 事务?