Pergunta

Este erro levou-me um tempo para encontrar ...

Considere este método:

public void foo(Set<Object> set)
{
    Object obj=set.iterator().next();
    set.remove(obj)
}

invoco o método com um conjunto de hash não-vazia, mas nenhum elemento vai ser removido!

Por que seria isso?

Foi útil?

Solução

Para um HashSet, isso pode ocorrer se hashCode do objeto muda depois de ter sido adicionado ao conjunto. O método HashSet.remove () pode então olhar no balde Hash errado e não conseguem encontrá-lo.

Isso provavelmente não aconteceria se você fez Iterator.remove (), mas em qualquer caso, armazenar objetos em um HashSet cuja hashCode mudança pode é um acidente esperando para acontecer (como você descobriu).

Outras dicas

enigma? Se Object.hashCode, Object.equals ou o "conjunto de hash" foram implementadas de forma incorrecta (ver, por exemplo, java.net.URL - uso URI).

Além disso, se o conjunto (direta ou indiretamente) contém em si, algo está estranho provável de acontecer (exatamente o que é a implementação e fase da lua dependente).

Qual é o tipo de implementação do conjunto e quais objetos estão dentro do set?

  • Se é um HashSet, certifique-se que o valor de hashCode do objeto () método se mantém constante entre set.put(...) e set.remove(...).
  • Se é um TreeSet, certifique-se de que não foram feitas modificações para o objeto que afetam comparação do conjunto ou método compareTo do objeto.

Em ambos os casos, o código entre set.put(...) e set.remove(...) viola o contrato definido pela respectiva implementação da classe. Como regra geral, é uma boa idéia usar objetos imutáveis ??como conteúdo set (e como chaves de mapa). Pela sua própria natureza de tais objetos não pode ser alterado enquanto eles são armazenados dentro de um conjunto.

Se você estiver usando alguma outra implementação set, verificar a sua JavaDoc para seu contrato; mas geralmente quer equals ou hashCode deve permanecer a mesma enquanto o objeto está contido no conjunto.

Além da falta '; após set.remove(obj), isso pode acontecer em três situações (citado de 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.

Você também pode tentar:

public void foo(Set<Object> set)
{
    Object obj=set.iterator().next();
    iterator.remove();
}

Caso seja:

public void foo(Set<Object> set)
{
    Iterator i = set.iterator();
    i.next();
    i.remove();
}

?

O bug poderia ser algo a ver com:

Remover public void ()

O comportamento de um iterador é não especificado se o subjacente recolha é modificado enquanto o iteração está em andamento de qualquer maneira diferente chamando este método.

( referência )

Eu não posso ajudar, mas sinto que (parte de) o problema é que o conjunto é passado por valor, não de referência. Eu não tenho muita experiência em Java, então eu poderia ser totalmente errado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top