这个bug花了我一段时间才找到...
考虑这种方法:
public void foo(Set<Object> set)
{
Object obj=set.iterator().next();
set.remove(obj)
}
我使用非空哈希集调用该方法,但不会删除任何元素!
为什么会这样?
对于 HashSet,如果对象的 hashCode 在添加到集合后发生更改,则会发生这种情况。然后 HashSet.remove() 方法可能会在错误的 Hash 桶中查找并找不到它。
如果您执行了 iterator.remove() ,这可能不会发生,但无论如何,将对象存储在其 hashCode 可以更改的 HashSet 中是等待发生的意外(正如您所发现的那样)。
谜?如果Object.hashCode
,Object.equals
或“散列集”实施不正确(例如,请参见java.net.URL
- 使用URI
)。
此外,如果集合(直接或间接)包含自身,则可能会发生一些奇怪的事情(确切地说是什么是实现和月相依赖)。
集合的实现类型是什么,集合内有哪些对象?
set.put(...)
和之间保持不变set.remove(...)
。compareTo
方法的对象进行修改。在这两种情况下,代码之间的代码都set.put(...)
违反set.remove(...)
了各自类实现定义的契约。根据经验,使用不可变对象作为设置内容(和 Map 键)是一个好主意。就其本质而言,此类对象在存储在集合中时无法更改。
如果您正在使用其他集合实现,请查看其 JavaDoc 以获取其合同;但当对象包含在集合中时,通常要么equals
保持hashCode
不变,要么保持不变。
除了缺少的';' 之后set.remove(obj)
,它可能在三种情况下发生(引自 javadoc)。
ClassCastException - if the type of the specified element is incompatible with this set (optional). NullPointerException - if the specified element is null and this set does not support null elements (optional). UnsupportedOperationException - if the remove method is not supported by this set.
你也可以试试:
public void foo(Set<Object> set)
{
Object obj=set.iterator().next();
iterator.remove();
}
应该是:
public void foo(Set<Object> set)
{
Iterator i = set.iterator();
i.next();
i.remove();
}
?
该错误可能与以下内容有关:
公共无效删除()
如果在迭代过程中以除调用此方法之外的任何方式修改了底层集合,则迭代器的行为是未指定的。
(参考)
我的类似案例:
这对我不起作用。我的班级组需要@Override equals和hashCode,如下所示:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Group other = (Group) obj;
if (id == null) {
if (other.id != null) return false;
} else if (!id.equals(other.id)) return false;
return true;
}
这迫使通过id字段比较 POJO,没有月相。
我不禁觉得(部分)问题是集合是按值传递的,而不是引用传递。不过,我在 Java 方面没有太多经验,所以我可能完全错了。