Domanda

Questo bug Mi ci volle un po 'per trovare ...

Considerate questo metodo:

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

invoco il metodo con un set hash non vuoto, ma nessun elemento sarà rimosso!

Perché mai?

È stato utile?

Soluzione

Per un HashSet, questo può verificarsi se i cambiamenti hashCode dell'oggetto dopo che è stato aggiunto al set. Il metodo HashSet.remove () può quindi cercare nel secchio Hash sbagliato e non riescono a trovarlo.

Questo probabilmente non accadrebbe se l'avete fatto iterator.remove (), ma in ogni caso, la memorizzazione di oggetti in un HashSet cui hashCode può cambiare è un incidente in attesa di accadere (come hai scoperto).

Altri suggerimenti

Puzzle? Se Object.hashCode, Object.equals o il "set di hash" sono stati implementati in modo non corretto (si veda ad esempio, java.net.URL - uso URI).

Anche se l'insieme (direttamente o indirettamente) stesso contiene, qualcosa di strano è probabile che accada (esattamente ciò che è l'attuazione e la fase della luna dipendente).

Qual è il tipo di implementazione del set e quali oggetti sono all'interno del set?

  • Se è un HashSet, verificare che il valore della hashCode dell'oggetto () metodo rimane costante tra set.put(...) e set.remove(...).
  • Se è un TreeSet, assicurarsi che non sono state apportate modifiche all'oggetto che influenzano comparatore del set o il metodo compareTo dell'oggetto.

In entrambi i casi, il codice tra set.put(...) e set.remove(...) viola il contratto definito dal rispettivo implementazione della classe. Come regola generale, è una buona idea usare oggetti immutabili come contenuti set (e come chiavi mappa). Per loro natura tali oggetti non possono essere modificati mentre sono memorizzati all'interno di un insieme.

Se si utilizza un altro set di implementazione, controlla la sua JavaDoc per il suo contratto; ma di solito o equals o hashCode deve rimanere lo stesso, mentre l'oggetto è contenuto nel set.

Al di là del mancante ';' dopo set.remove(obj), può avvenire in tre situazioni (citato da 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.

Si può anche provare:

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

Dovrebbe essere:

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

Il bug potrebbe essere qualcosa a che fare con:

  

vuoto remove pubblico ()

     

Il comportamento di un iteratore è   non specificato se il sottostante   raccolta viene modificata mentre il   iterazione è in corso in qualsiasi modo   diverso chiamando questo metodo.

( Riferimento )

Non riesco a fare a meno di sentire che (in parte) il problema è che il set viene passato per valore, non riferimento. Non ho molta esperienza in Java, però, in modo da poter essere totalmente sbagliata.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top