这是有目的的
我想知道为什么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()
生成了新的数组,因此这样做是安全的,而且这样做的效率要高得多(避免了一堆不必要的副本).