web-dev-qa-db-fra.com

Java HashSet avec un critère d'égalité personnalisé?

Je cherchais quelque chose qui ressemble aux Java capacité de TreeSet à recevoir un comparateur personnalisé au moment de l'instanciation, donc je n'avais pas besoin d'utiliser les critères d'égalité par défaut (et de code de hachage) de l'objet.

Le plus proche que j'ai pu trouver était d'envelopper mes objets dans une classe personnalisée privée, mais cela semble hacky :( Cela finit par être une sorte de thème récurrent lors de la programmation, donc je me demandais s'il y avait déjà quelque chose à utiliser pour nous. Peut-être dans les bibliothèques communes?

Merci

36
devoured elysium

Non, vous avez trouvé exactement la solution que vous êtes censé utiliser.

Même pour TreeSet, c'est désapprouvé pour utiliser des critères de comparaison qui ne sont pas compatibles avec equals:

Notez que l'ordre maintenu par un ensemble trié (qu'un comparateur explicite soit fourni ou non) doit être cohérent avec égal si l'ensemble trié doit implémenter correctement l'interface Set.

(Je ne sais pas pour Apache Commons, mais Guava spécifiquementrejeté demande ce genre de chose.)

15
Louis Wasserman

Il existe quelques cadres de collections tiers qui permettent une logique d'égalité personnalisée. C'est parfait pour remplacer l'égalité pour les objets dont vous ne pouvez pas modifier la source.

Les cartes/ensembles de Trove prennent en charge l'utilisation de stratégies de hachage personnalisées, vous permettant d'ajuster les collections en fonction des caractéristiques des données d'entrée. Cette fonctionnalité vous permet également de définir des fonctions de hachage lorsqu'il n'est pas possible de remplacer Object.hashCode ().

Pour y parvenir, tout type nécessitant une correction standard doit implémenter l'interface HE-Collection EqualsAndHashCorrection. Cette interface définit les méthodes hashCodeInHeCollection () et equalsInHeCollection (Object), qui servent de correction pour les méthodes implémentées incorrectes hashCode () et equals (Object).

3
Steve Kuo

Vous avez raison, lorsque vous souhaitez utiliser l'un des Trees (TreeMap, TreeSet), les objets que vous ajoutez doivent implémenter Comparable.

Pour les types primitifs, Java a résolu cela pour vous.
Pour les objets personnalisés, vous avez 3 possibilités:

  1. Un de vos objets a déjà un identifiant unique de type primitif ou un type qui implémente déjà compareTo() (comme String) Utilisez ensuite ce champ pour compareTo, si les valeurs des autres ne sont pas important pour l'égalité. (Mais alors equals() ne doit également utiliser que ce champ)

  2. Utilisez EqualsBuilder d'Apache: cela fonctionne avec la réflexion et n'est pas la solution la plus rapide

  3. Écrivez-le vous-même, lisez quelques tutoriels pour y parvenir: par exemple:

Josh Bloch: Effectif Java 2nd Edition

Mais n'oubliez pas que equals() et compareTo() doivent être compatibles (et hashCode() aussi), de sorte que vous ne violez pas le contrat égal. (Le contrat lui-même est moins compréhensible, mais il devient clair si vous respectez l'un de ces égaux tutoriels.)

Ou oubliez tout cela et utilisez un HashSet, HashMap.

3
AlexWien