363 votes

Conversion de l'ordinal d'un enum en type d'enum

J'ai le type enum ReportTypeEnum qui sont transmises entre les méthodes dans toutes mes classes, mais je dois ensuite les transmettre à l'URL et j'utilise donc la méthode ordinal pour obtenir la valeur int. Après l'avoir récupérée dans mon autre page JSP, je dois la reconvertir en un fichier ReportTypeEnum pour que je puisse continuer à le faire passer.

Comment puis-je convertir l'ordinal en ReportTypeEnum ?

Utilisation de Java 6 SE.

1 votes

Il n'y a pas de Java 6 EE, jusqu'à présent (AFAIK). Il y a Java SE 6, et Java EE 5.

727voto

Joachim Sauer Points 133411

Pour convertir un ordinal en sa représentation enum, vous pouvez procéder comme suit :

ReportTypeEnum value = ReportTypeEnum.values()[ordinal];

Veuillez noter les limites du tableau.

Notez que chaque appel à values() retourne un tableau nouvellement cloné qui peut avoir un impact négatif sur les performances. Vous voudrez peut-être mettre le tableau en cache s'il est appelé souvent.

Exemple de code pour la mise en cache values() .


Cette réponse a été modifiée afin d'inclure le feedback donné dans les commentaires.

1 votes

J'ai mis en œuvre cette solution et elle ne fonctionne pas pour moi. Elle renvoie que la valeur ordinale n'est pas garantie pour correspondre à l'ordre dans lequel les types énumérés sont ajoutés. Je ne sais pas si c'est ce que préconise cette réponse, mais je voulais tout de même avertir les personnes concernées.

0 votes

@IcesDante : l'ordinal est certainement garanti pour correspondre à l'ordre des valeurs de l'énumération dans la source. Si vous observez un comportement différent, alors quelque chose d'autre doit être incorrect. Ma réponse ci-dessus est cependant sous-optimale pour toutes les raisons exposées dans les autres réponses.

0 votes

@JoachimSauer IcedDante veut peut-être dire que l'ordinal peut ne pas correspondre s'il a été produit et sauvegardé par une version antérieure de la source, dans laquelle les valeurs de l'enum étaient dans un ordre différent.

145voto

oxbow_lakes Points 70013

C'est presque certainement une mauvaise idée . Certes, si l'ordinal est de-facto persisté (par exemple parce que quelqu'un a mis l'URL en signet) - cela signifie que vous devez toujours conserver l'adresse de l'utilisateur. enum à l'avenir, ce qui peut ne pas être évident pour les responsables du code à l'avenir.

Pourquoi ne pas coder le enum en utilisant myEnumValue.name() (et décoder via ReportTypeEnum.valueOf(s) ) à la place ?

0 votes

Je suis d'accord, c'est la meilleure solution.

34 votes

Que se passe-t-il si vous changez le nom de l'enum (mais que vous conservez l'ordre) ?

8 votes

@Arne - Je pense que c'est beaucoup moins probable que l'arrivée d'une personne inexpérimentée ajoutant une value soit au début, soit à sa position alphabétique/logique correcte. (Par logique, j'entends par exemple TimeUnit les valeurs ont une position logique)

113voto

QED Points 5350

Si je dois utiliser values() beaucoup :

enum Suit {
   Hearts, Diamonds, Spades, Clubs;
   public static final Suit values[] = values();
}

Pendant ce temps, où que ce soit, java :

Suit suit = Suit.values[ordinal];

Si vous voulez que le tableau soit privé, je vous en prie :

private static final Suit values[] = values();
public static Suit get(int ordinal) { return values[ordinal]; }

...

Suit suit = Suit.get(ordinal);

Attention aux limites de votre tableau.

4 votes

+1 c'est de loin la meilleure solution IMHO parce que l'on peut passer des ordinaux autour, notamment dans Android.os.Message.

16 votes

C'est très inquiétant car les tableaux sont mutables . Même si values[] est final, cela n'empêche pas Suit.values[0] = Suit.Diamonds; quelque part dans votre code. Dans l'idéal, cela ne se produira jamais, mais le principe général de la ne pas exposer les champs mutables tient toujours. Pour cette approche, envisagez d'utiliser Collections.unmodifiableList ou autre à la place.

1 votes

Que diriez-vous de - private static final Suit values[] = values() ; public static Suit[] getValues() { return values ; }

19voto

jmkelm08 Points 249

Je suis d'accord avec la plupart des gens pour dire que l'utilisation de l'ordinal est probablement une mauvaise idée. Je résous généralement ce problème en donnant à l'énumération un constructeur privé qui peut prendre par exemple une valeur DB, puis créer un fichier statique de l'énumération. fromDbValue similaire à celle de la réponse de Jan.

public enum ReportTypeEnum {
    R1(1),
    R2(2),
    R3(3),
    R4(4),
    R5(5),
    R6(6),
    R7(7),
    R8(8);

    private static Logger log = LoggerFactory.getLogger(ReportEnumType.class);  
    private static Map<Integer, ReportTypeEnum> lookup;
    private Integer dbValue;

    private ReportTypeEnum(Integer dbValue) {
        this.dbValue = dbValue;
    }

    static {
        try {
            ReportTypeEnum[] vals = ReportTypeEnum.values();
            lookup = new HashMap<Integer, ReportTypeEnum>(vals.length);

            for (ReportTypeEnum  rpt: vals)
                lookup.put(rpt.getDbValue(), rpt);
         }
         catch (Exception e) {
             // Careful, if any exception is thrown out of a static block, the class
             // won't be initialized
             log.error("Unexpected exception initializing " + ReportTypeEnum.class, e);
         }
    }

    public static ReportTypeEnum fromDbValue(Integer dbValue) {
        return lookup.get(dbValue);
    }

    public Integer getDbValue() {
        return this.dbValue;
    }

}

Vous pouvez désormais modifier l'ordre sans modifier la consultation et vice versa.

0 votes

C'est la bonne réponse. Je suis surpris qu'elle ait obtenu si peu de points par rapport à d'autres réponses plus directes mais potentiellement invalides (en raison de changements de code à venir).

0 votes

D= ( ) Seule solution pour les drapeaux où l'entier peut être n'importe quoi (et n'est pas ordonné) comme 0xDEAD par exemple.

8voto

Jan Points 4766

Vous pourrait utiliser une table de consultation statique :

public enum Suit {
  spades, hearts, diamonds, clubs;

  private static final Map<Integer, Suit> lookup = new HashMap<Integer, Suit>();

  static{
    int ordinal = 0;
    for (Suit suit : EnumSet.allOf(Suit.class)) {
      lookup.put(ordinal, suit);
      ordinal+= 1;
    }
  }

  public Suit fromOrdinal(int ordinal) {
    return lookup.get(ordinal);
  }
}

3 votes

Voir aussi Enums .

13 votes

Wow ! Juste wow ! C'est chouette, bien sûr, mais... vous savez, le programmeur C en moi hurle de douleur en voyant que vous allouez un HashMap complet et que vous effectuez des recherches à l'intérieur de ce HashMap JUSTE pour gérer 4 constantes : pique, coeur, carreau et trèfle ! Un programmeur C allouerait 1 octet pour chacune : 'const char CLUBS=0;' etc... Oui, la consultation d'un HashMap est O(1), mais la mémoire et les frais généraux du CPU d'un HashMap, dans ce cas, le rendent beaucoup plus lent et gourmand en ressources que l'appel direct de .values() ! Pas étonnant que Java soit si gourmand en mémoire si les gens écrivent comme ça...

3 votes

Tous les programmes ne requièrent pas la performance d'un jeu triple A. Dans de nombreux cas, il est justifié de troquer la mémoire et le processeur contre la sécurité des types, la lisibilité, la maintenabilité, le support multiplateforme, la collecte des déchets, etc. Les langages de niveau supérieur existent pour une raison.

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