k31*_*159 3 java collections list
Stream.toList的实现(和文档)是这样的:
Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())))
Run Code Online (Sandbox Code Playgroud)
我想知道为什么需要将返回的列表Arrays.asList复制到新的ArrayList. 仅返回以下内容还不够吗?
Collections.unmodifiableList(Arrays.asList(this.toArray()))
Run Code Online (Sandbox Code Playgroud)
我想知道,如果我编写一个返回它创建的列表的方法,如果我不费心制作它的防御性副本,是否会出现任何问题?
我想知道为什么 Arrays.asList 返回的列表需要复制到新的 ArrayList 中。仅返回以下内容还不够吗?
.toArray()我们在谈论哪一个?如果我们谈论的是来自 的那个,那么你是对的:该方法j.u.Collection的 javadoc保证它是一个新分配的数组,因此不需要制作防御性副本。然而,这不是这里涉及的:我们正在讨论's 。它的 javadoc 短得多:toArray()toArray()j.u.s.Stream.toArray()
/**
* 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
*/
Run Code Online (Sandbox Code Playgroud)
不像j.u.Collection toArray(),此 javadoc 没有对该数组的性质做任何注释。因此,显然,javadoc 中的默认 implStream并不假定该数组一定是“安全”的(“安全”的意思是:以后不会被修改)。
我想你知道,但我要说得清楚一点:
Arrays.asList几乎总是一个错误。这是一个两全其美的列表:它在您传递给它的数组周围创建了一个轻包装器。所以,set()可行(因为foo[x] = value;这是可能的,而且确实是实现方式),但.add()不行(因为你无法更改数组的大小)。该列表不是一成不变的(即,如果将其传递给您直接控制之外的代码,您需要广泛记录,或者制作防御性副本),但也不是一个功能齐全的列表。使用List.of,它会生成完全不可变的列表 - 您可以将列表传递给您喜欢的任何人,而不必担心失去完整性控制。
编辑:并解释为什么它的Collections.unmodifiableList(new ArrayList<...) 而不是- make 上的那些静态方法在其中时抛出 NPE 的List.copyOf不可变列表,但流可以有Listnullnull ,但流可以有,所以你不能使用它。此编辑是由 @Rob Spoor 的评论带来的:)
请注意,您找到的代码仅仅是默认实现 - 流的任何特定实现都可以自由地提出更好的方法来执行此操作。几乎您必然会遇到的每个实现都会覆盖定义。例如,如果您调用 arraylist's stream(),您最终会得到此实现,它来自streamops,并且与核心库中的所有集合使用的代码路径相同。因此,您最终使用的实际代码是这样的:
@Override
public List<P_OUT> toList() {
return SharedSecrets.getJavaUtilCollectionAccess()
.listFromTrustedArrayNullsAllowed(this.toArray());
}
Run Code Online (Sandbox Code Playgroud)
这里的“可信数组”是指传递给它的数组保证不会在您的控制下发生变化。编译器无法强制执行这种保证,但是 arraylist(事实上,所有未损坏的集合,考虑到 javadoc 的j.u.Collection要求!)toArray()会创建新数组,因此这样做是安全的,而且效率更高(避免了一堆不必要的副本)。
| 归档时间: |
|
| 查看次数: |
246 次 |
| 最近记录: |