addAll()实现 -- Java

3

AbstractCollectionaddAll() 方法实现如下:

public boolean addAll(Collection<? extends E> c) { 
    boolean modified = false;
    for (E e : c) if (add(e)) modified = true; 
    return modified;
}

所以,如果参数中的c是一个包含3个元素的集合,可能会出现这样的情况,即前两个元素被添加了,但第三个元素由于某些原因未被添加(我现在想不出来)。在这种情况下,addAll()操作-将所有这3个元素添加到基础集合中-未被执行,并且addAll()返回false,就像应该的那样。然而,前两个元素仍然存在,开发者可能期望它们不应该存在(?) HashSet在其使用类型为Collection的单参数构造函数中使用此addAll().
因此,开发者可能会得到一个HashSet实例,其中包含他的集合的一部分,而他正在寻找整个集合,而这发生时没有任何警告。
涉及的方法-- HashMapput()HashSetadd()--似乎足够简单--在这些操作期间似乎不会出错--但还是有可能出错。我有什么遗漏吗?

很好,我之前不知道这个。 - arynaq
5个回答

6
< p > Collection#addAll(...)方法的合同仅表示它返回true,如果集合(this)被修改。它不能保证添加操作是原子性或完整性。


5
在这种情况下,addAll()操作——将这3个元素全部添加到基础集合中的操作未执行,addAll()返回了false,正如它应该做的那样。
如果成功添加了任何一个元素,则addAll()返回true,而不是所有元素都被添加。您可以从您发布的代码中看到这一点:只要add()调用返回true,modified就会立即设置为true。

3
正如其他人已经提到的那样,如果成功添加任何元素,则该方法返回true
此外:http://docs.oracle.com/javase/6/docs/api/java/util/Collection.html#add(E) 如果一个集合因为任何其他原因而拒绝添加特定元素,而不是因为它已经包含该元素,则它必须抛出异常(而不是返回false)。这保留了在此调用返回后集合始终包含指定元素的不变性。
因此,根据您提供的addAll实现,如果未添加元素并且没有抛出异常,则说明元素已经存在于集合中。

2
因此,开发人员可能会得到一个包含部分集合的HashSet实例,而他正在寻找整个集合。这种情况发生时没有任何警告。
不是这样的。Set.add返回false表明已经存在。唯一的例外是有大小限制的有界集合,在这种情况下,开发人员应该知道它是一个有界集合,并且不一定包含所有元素。对于大多数集合API中的集合,调用addAll保证如果您使用相同的集合调用containsAll,则其将返回true。例如,这将打印true
Set<T> set1 = new HashSet<>();
Set<T> set2 = new HashSet<>();
// Add stuff to the sets
set1.addAll(set2);
System.out.println(set1.containsAll(set2));

这将异常情况限制在您在答案中所说的内容上,我想不出其他任何问题。然而,HashSet 的使用仍然有点奇怪,它没有完全覆盖这一点。 - Roam

1

javadoc中写道,如果当前Collection被修改,则addAll返回true(否则返回false)。

这意味着即使只添加了一个元素,该方法也会返回true。将返回值视为指示器,指示此集合是否作为方法调用的结果而修改,而不是所有元素都被添加。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接