Question

Ce bug m'a fallu un certain temps pour trouver ...

Considérez cette méthode:

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

J'invoque la méthode avec un ensemble de hachage non vide, mais aucun élément sera supprimé!

Pourquoi serait-ce?

Était-ce utile?

La solution

Pour un HashSet, cela peut se produire si les changements hashCode de l'objet après qu'il a été ajouté à l'ensemble. La méthode HashSet.remove () peut alors regarder dans le mauvais seau Hash et ne parviennent pas à le trouver.

Ce ne serait probablement pas se produire si vous avez Iterator.remove (), mais dans tous les cas, le stockage d'objets dans un HashSet dont hashCode peut changer est un accident qui devait arriver (comme vous avez découvert).

Autres conseils

Casse-tête? Si Object.hashCode, Object.equals ou le "jeu de hachage" ont été mises en œuvre de manière incorrecte (voir par exemple, java.net.URL - utilisation URI).

Aussi, si l'ensemble (directement ou indirectement) contient lui-même, quelque chose est susceptible de se produire étrange (exactement ce qui est la mise en œuvre et la phase de la personne à charge lune).

Quel est le type de mise en œuvre de l'ensemble et quels objets sont à l'intérieur du jeu?

  • Si c'est une méthode HashSet, assurez-vous que la valeur de hashCode de l'objet () reste constant entre set.put(...) et set.remove(...).
  • Si c'est un TreeSet, assurez-vous que non modifications ont été apportées à l'objet qui affectent le comparateur ou la méthode de compareTo de l'objet de l'ensemble.

Dans les deux cas, le code entre set.put(...) et set.remove(...) constitue une violation du contrat défini par la mise en œuvre de classe respective. En règle générale, il est une bonne idée d'utiliser des objets immuables en tant que contenu de jeu (et les clés de la carte). De par leur nature même, ces objets ne peuvent pas être modifiés pendant qu'ils sont stockés dans un ensemble.

Si vous utilisez une autre implémentation ensemble, consultez son JavaDoc pour son contrat; mais le plus souvent soit equals ou hashCode doivent rester les mêmes alors que l'objet est contenu dans l'ensemble.

Au-delà du manque ';' après set.remove(obj), il peut se produire dans trois situations (cité 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.

Vous pouvez aussi essayer:

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

Faut-il être:

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

Le bug pourrait être quelque chose à voir avec:

  

supprimer public void ()

     

Le comportement d'un itérateur est   Non spécifié si le sous-jacent   collection est modifiée pendant que le   itération est en cours de quelque manière que   autrement que par appel à cette méthode.

( de référence)

Je ne peux pas empêcher de penser que (en partie) le problème est que l'ensemble est passé par valeur, pas de référence. Je n'ai pas beaucoup d'expérience en Java, donc je pourrais être tout à fait tort.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top