88 votes

Pourquoi compareTo sur un Enum est final en Java ?

Un enum en Java met en œuvre la fonction Comparable interface. Il aurait été bien de remplacer Comparable 's compareTo mais ici il est marqué comme final. L'ordre naturel par défaut sur Enum 's compareTo est l'ordre de la liste.

Quelqu'un sait-il pourquoi les enums Java ont cette restriction ?

118voto

Zach Scrivena Points 15052

Pour la cohérence je suppose... quand vous voyez un enum le type, vous savez pour un fait que son ordre naturel est l'ordre dans lequel les constantes sont déclarées.

Pour contourner cela, vous pouvez facilement créer votre propre Comparator<MyEnum> et l'utiliser chaque fois que vous avez besoin d'une commande différente :

enum MyEnum
{
    DOG("woof"),
    CAT("meow");

    String sound;    
    MyEnum(String s) { sound = s; }
}

class MyEnumComparator implements Comparator<MyEnum>
{
    public int compare(MyEnum o1, MyEnum o2)
    {
        return -o1.compareTo(o2); // this flips the order
        return o1.sound.length() - o2.sound.length(); // this compares length
    }
}

Vous pouvez utiliser le Comparator directement :

MyEnumComparator c = new MyEnumComparator();
int order = c.compare(MyEnum.CAT, MyEnum.DOG);

ou l'utiliser dans des collections ou des tableaux :

NavigableSet<MyEnum> set = new TreeSet<MyEnum>(c);
MyEnum[] array = MyEnum.values();
Arrays.sort(array, c);    

Pour plus d'informations :

37voto

Thomas Paine Points 61

Fournir une implémentation par défaut de compareTo qui utilise l'ordre du code source est bien ; le rendre définitif était un faux pas de la part de Sun. L'ordinal tient déjà compte de l'ordre de déclaration. Je suis d'accord que dans la plupart des situations un développeur peut simplement ordonner logiquement ses éléments, mais parfois on veut que le code source soit organisé d'une manière qui rende la lisibilité et la maintenance primordiales. Par exemple :

  //===== SI BYTES (10^n) =====//

  /** 1,000 bytes. */ KILOBYTE (false, true,  3, "kB"),
  /** 106 bytes. */   MEGABYTE (false, true,  6, "MB"),
  /** 109 bytes. */   GIGABYTE (false, true,  9, "GB"),
  /** 1012 bytes. */  TERABYTE (false, true, 12, "TB"),
  /** 1015 bytes. */  PETABYTE (false, true, 15, "PB"),
  /** 1018 bytes. */  EXABYTE  (false, true, 18, "EB"),
  /** 1021 bytes. */  ZETTABYTE(false, true, 21, "ZB"),
  /** 1024 bytes. */  YOTTABYTE(false, true, 24, "YB"),

  //===== IEC BYTES (2^n) =====//

  /** 1,024 bytes. */ KIBIBYTE(false, false, 10, "KiB"),
  /** 220 bytes. */   MEBIBYTE(false, false, 20, "MiB"),
  /** 230 bytes. */   GIBIBYTE(false, false, 30, "GiB"),
  /** 240 bytes. */   TEBIBYTE(false, false, 40, "TiB"),
  /** 250 bytes. */   PEBIBYTE(false, false, 50, "PiB"),
  /** 260 bytes. */   EXBIBYTE(false, false, 60, "EiB"),
  /** 270 bytes. */   ZEBIBYTE(false, false, 70, "ZiB"),
  /** 280 bytes. */   YOBIBYTE(false, false, 80, "YiB");

L'ordre ci-dessus semble bon dans le code source, mais ce n'est pas la façon dont l'auteur pense que le compareTo devrait fonctionner. Le comportement souhaité pour le compareTo est d'avoir un classement par nombre d'octets. L'ordre du code source qui permettrait d'obtenir ce résultat dégrade l'organisation du code.

En tant que client d'une énumération, je ne pourrais pas me soucier moins de la façon dont l'auteur a organisé son code source. Je veux que leur algorithme de comparaison ait un sens, cependant. Sun a inutilement mis les auteurs de code source dans une impasse.

6voto

Martin OConnor Points 1877

Les valeurs des énumérations sont précisément ordonnées logiquement selon l'ordre dans lequel elles sont déclarées. Cela fait partie des spécifications du langage Java. Il s'ensuit que les valeurs d'une énumération ne peuvent être comparées que si elles sont membres de la même Enum. La spécification veut en outre garantir que l'ordre de comparaison renvoyé par compareTo() est le même que l'ordre dans lequel les valeurs ont été déclarées. C'est la définition même d'une énumération.

0voto

random coder Points 1

Un autre exemple : un enum de cartes à jouer avec des membres Rank et Suit où vous voulez que compareTo retourne non pas l'ordre lexical des 52 valeurs mais la comparaison des rangs. En fait, comme le compareTo automatique compare sur l'ordre lexical, il ne retournera jamais 0.

-1voto

Bombe Points 34185

Si vous souhaitez modifier l'ordre naturel des éléments de votre enum, modifiez leur ordre dans le code source.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X