Java SortedSet + comparatore, la coerenza con equals () domanda
-
19-09-2019 - |
Domanda
Mi piacerebbe avere un SortedSet delle collezioni (si imposta, in questo caso, ma non necessariamente in generale), che le specie di dimensioni Collection. Questo sembra violare il divieto di avere il comparatore essere coerente con equals () -. Vale a dire, due collezioni possono essere disuguale (avendo elementi diversi), ma confrontare allo stesso valore (perché hanno lo stesso numero di elementi)
fittiziamente, potrei anche mettere in modi comparatore per ordinare gruppi di uguali dimensioni, ma l'uso del genere non avrei approfittare di questo, e non c'è davvero un modo utile + intuitivo per confrontare le collezioni di uguali dimensioni (almeno, nel mio caso particolare), in modo tale che sembra uno spreco.
Questo caso di incoerenza sembrare un problema?
Soluzione
Come ChssPly76 ha scritto in un commento, è possibile utilizzare hashCode per decidere la chiamata compareTo nel caso in cui due collezioni hanno la stessa dimensione, ma non sono uguali. Questo funziona bene, tranne in rari casi in cui si dispone di due collezioni con le stesse dimensioni, non sono uguali, ma hanno lo stesso hashCode. Certo, le probabilità che questo accada sono piuttosto piccole, ma è concepibile. Se si vuole essere molto attenti, invece di hashCode, utilizzare al posto System.identityHashCode. Questo dovrebbe dare un numero unico per ogni collezione, e non si dovrebbe ottenere le collisioni.
Alla fine della giornata, questo ti dà la funzionalità di avere le collezioni del Set ordinati per dimensione, con ordine arbitrario nel caso di due collezioni con dimensione corrispondente. Se questo è tutto ciò che serve, non è molto più lento rispetto al solito confronto sarebbe. Se è necessario l'ordine di essere coerenti tra le diverse istanze JVM, questo non funzionerà e dovrete farlo in qualche altro modo.
pseudocodice:
if (a.equals(b)) {
return 0;
} else if (a.size() > b.size()) {
return 1;
} else if (b.size() > a.size()) {
return -1;
} else {
return System.identityHashCode(a) > System.identityHashCode(b) ? 1 : -1;
}
Altri suggerimenti
SortedSet
interfaccia estende Set
e quindi devono essere conformi al contratto indicato nella specifica Set
.
L'unico modo possibile per raggiungere questo obiettivo è quello di avere il metodo equal()
comportamento del vostro elemento essere coerente con il Comparator
-. La ragione di ciò è che Set
nucleo funziona basato sulla parità, mentre SortedSet
opera basata sul confronto
Ad esempio, metodo add()
definito nella interfaccia set base specifica che non è possibile aggiungere un elemento al dispositivo se non v'è già un elemento il cui metodo equal()
sarebbe tornato vero con questo nuovo elemento come argomento. Beh, SortedSet
non usa equal()
, utilizza compareTo()
. Quindi, se le vostre dichiarazioni compareTo()
false
vostro elemento verrà aggiunto anche se equals()
dovessimo tornare true
, rompendo così il contratto Set
.
Niente di tutto questo è un pratica problema di per sé, tuttavia. comportamento SortedSet
è sempre coerente, anche se compare()
vs equals()
non lo sono.
Questo sembra violare il divieto per avere il comparatore essere coerente con equals () - vale a dire, due collezioni può essere disuguale (avendo differente elementi), ma confronto alla stessa valore (perché hanno la stessa numero di elementi).
Non v'è alcun obbligo, né dichiarato (nel Javadoc) o implicita, che un Comparator
essere coerente con l'implementazione di un oggetto di boolean equals(Object)
.
Si noti che Comparable
e Comparator
sono interfacce distinte con scopi diversi. Comparable
viene utilizzato per definire un ordine di 'naturale' per una classe. In tale contesto, sarebbe una cattiva idea per equals
e compateTo
incoerente. Al contrario, un Comparator
viene utilizzato quando si desidera utilizzare un ordine diverso per l'ordine naturale di una classe.
EDIT:. Ecco il punto completo dal Javadoc per SortedSet
Si noti che l'ordinamento mantenuto da un set ordinato (anche un esplicito comparatore è previsto) deve essere coerente con eguali se l'ordinato set è quello di attuare correttamente il Set interfaccia. (Vedere la Paragonabile interfaccia o comparatore interfaccia per una definizione precisa di coerenza con eguali.) Questo è così perché il Set interfaccia è definita in termini di l'operazione è uguale, ma un ordinato set esegue tutti i confronti di elementi utilizzando il suo compareTo (o confrontare) metodo, quindi due elementi che sono ritenuto uguale con tale metodo, da punto di vista del set ordinato, pari. Il comportamento di un insieme ordinato è ben definito anche se il suo ordine è incompatibile con eguali; e 'solo non riesce a rispettare il contratto generale l'interfaccia Set.
Ho evidenziato la frase finale. Il punto è che una tale SortedSet funzionerà come si sarebbe molto probabilmente si aspetterebbe, ma il comportamento di alcune operazioni non corrispondere esattamente alla specifica Set
... perché la specifica definisce il loro comportamento in termini di metodo equals
.
Quindi, in realtà, non vi un requisito dichiarato per consistenza (mio errore), ma le conseguenze di ignorare non sono così male come si potrebbe pensare. Naturalmente, spetta a decidere se si dovrebbe fare questo. A mio avviso, dovrebbe essere OK, a condizione che si commenta il codice a fondo e assicurarsi che la SortedSet non si 'fuga'.
Tuttavia, non è chiaro per me che un comparatore per collezioni che guarda solo a un collezioni "dimensione" è andare a lavorare ... dal punto di vista semantico. Voglio dire, non si vuole veramente dire che tutte le collezioni con (diciamo) 2 elementi sono uguali? Ciò significa che il set può sempre e solo contenere una collezione di qualsiasi dimensione ...
Non v'è alcun motivo per cui un Comparator
deve restituire gli stessi risultati equals()
. In realtà, l'API Comparator
è stata introdotta perché equals()
solo non è sufficiente: se si desidera ordinare una raccolta, è necessario sapere se due elementi sono minore o maggiore
E 'un po' strano che SortedSet come parte della API standard rompe il contratto definito nell'interfaccia Imposta e utilizza il comparatore per definire l'uguaglianza al posto del metodo equals, ma è così che è.
Se il problema reale è quello di ordinare una collezione di collezioni in base alle dimensioni delle collezioni containted, si sono meglio di una lista, che è possibile ordinare tramite Collections.sort (Lista, comparatore>);