web-dev-qa-db-fra.com

Est-il acceptable d'aller à l'encontre des noms en majuscules pour les énumérations afin de simplifier leur représentation de chaîne?

Plusieurs fois, j'ai vu des gens utiliser des majuscules ou même des minuscules pour les constantes enum, par exemple:

enum Color {
  red,
  yellow,
  green;
}

Cela rend le travail avec leur forme de chaîne simple et facile, si vous voulez faire throw new IllegalStateException("Light should not be " + color + "."), par exemple.

Cela semble plus acceptable si l'énumération est private, mais je ne l'aime toujours pas. Je sais que je peux créer un constructeur enum avec un champ String, puis remplacer toString pour retourner ce nom, comme ceci:

enum Color {
  RED("red"),
  YELLOW("yellow"),
  GREEN("green");

  private final String name;

  private Color(String name) { 
    this.name = name 
  }

  @Override public String toString() {
    return name; 
  }
}

Mais regardez combien de temps cela dure. C'est ennuyeux de continuer à faire si vous avez un tas de petites énumérations que vous voulez garder simples. Est-il correct d'utiliser simplement des formats de cas non conventionnels ici?

14
codebreaker

La réponse courte est, bien sûr, de savoir si vous voulez rompre avec les conventions de dénomination pour ce qui sont essentiellement des constantes ... Citant les JLS :

Noms constants

Les noms des constantes dans les types d'interface doivent être, et les variables finales des types de classe peuvent être conventionnellement, une séquence d'un ou plusieurs mots, acronymes ou abréviations, tous en majuscules, avec des composants séparés par des caractères de soulignement "_". Les noms constants doivent être descriptifs et ne pas être abrégés inutilement. Classiquement, ils peuvent être n'importe quelle partie appropriée du discours.

La réponse longue, en ce qui concerne l'utilisation de toString(), est certainement la méthode à remplacer si vous voulez une représentation plus lisible des valeurs enum. Citant de Object.toString() (soulignement le mien):

Renvoie une représentation sous forme de chaîne de l'objet. En général, la méthode toString renvoie une chaîne qui "représente textuellement" cet objet . Le résultat devrait être une représentation concise mais informative facile à lire pour une personne . Il est recommandé que toutes les sous-classes remplacent cette méthode.

Maintenant, je ne sais pas pourquoi certaines des réponses ont dérivé pour parler de la conversion de enums en va-et-vient avec des valeurs de String, mais je vais juste donner mon avis ici également. Une telle sérialisation des valeurs enum peut être facilement prise en charge en utilisant les méthodes name() ou ordinal(). Les deux sont final et vous pouvez donc être sûr des valeurs retournées tant que les noms ou le positionnement des valeurs ne changent pas. Pour moi, c'est un marqueur assez clair.

Ce que je comprends de ce qui précède est: aujourd'hui, vous voudrez peut-être décrire YELLOW comme simplement "jaune". Demain, vous voudrez peut-être le décrire comme "Pantone Minion Yellow" . Ces descriptions devraient être renvoyées en appelant toString(), et je ne m'attendrais pas à ce que name() ou ordinal() changent. Si je le fais, c'est quelque chose que je dois résoudre au sein de ma base de code ou de mon équipe, et devient une plus grande question qu'un simple style de nommage enum.

En conclusion, si tout ce que vous avez l'intention de faire est d'enregistrer une représentation plus lisible de vos valeurs enum, je vous suggérerai toujours de vous en tenir aux conventions, puis de remplacer toString(). Si vous avez également l'intention de les sérialiser dans un fichier de données ou vers d'autres destinations non Java, vous avez toujours les méthodes name() et ordinal() pour vous sauvegarder, donc il n'y a pas besoin de s'inquiéter remplacer toString().

14
h.j.k.

Ne modifiez pas ENUM c'est juste une mauvaise odeur de code. Soit une énumération une énumération et une chaîne une chaîne.

Utilisez plutôt un convertisseur CamelCase pour les valeurs de chaîne.

throw new IllegalStateException("Light should not be " + CamelCase(color) + ".");

Il existe de nombreuses bibliothèques open source qui résolvent déjà ce problème pour Java.

http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/CaseFormat.html

5
Reactgular

Envoi d'énumérations entre mon Java et une base de données ou une application cliente, je finis souvent par lire et écrire les valeurs d'énumération sous forme de chaînes. toString() est appelée implicitement lors de la concaténation de chaînes. toString () sur certaines énumérations signifiait que parfois je pouvais juste

"<input type='checkbox' value='" + MY_CONST1 + "'>"

et parfois je devais me rappeler d'appeler

"<input type='checkbox' value='" + MY_CONST1.name() + "'>"

ce qui a conduit à des erreurs, donc je ne fais plus ça. En fait, je ne remplace pas les méthodes any sur Enum parce que si vous les jetez dans suffisamment de code client, vous finirez par briser les attentes de quelqu'un.

Créez votre propre nouveau nom de méthode, comme public String text() ou toEnglish() ou autre.

Voici une petite fonction d'aide qui pourrait vous faire économiser de la frappe si vous avez beaucoup d'énumérations comme ci-dessus:

public static String ucFirstLowerRest(String s) {
    if ( (s == null) || (s.length() < 1) ) {
        return s;
    } else if (s.length() == 1) {
        return s.toUpperCase();
    } else {
        return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
    }
}

Il est toujours facile d'appeler .toUpperCase () ou .toLowerCase () mais le retour en casse mixte peut être délicat. Considérez la couleur, "bleu de France". La France est toujours en majuscule, donc vous voudrez peut-être ajouter une méthode textLower () à votre énumération si vous rencontrez cela. Lorsque vous utilisez ce texte au début d'une phrase, par rapport au milieu d'une phrase, par rapport à un titre, vous pouvez voir comment une seule méthode toString() va échouer. Et cela ne touche même pas les caractères illégaux dans les identificateurs Java, ou qui sont difficiles à taper car ils ne sont pas représentés sur les claviers standard ou les caractères qui n'ont pas de casse ( Kanji, etc.).

enum Color {
  BLEU_DE_FRANCE {
    @Override public String textTc() { return "Bleu De France"; }
    @Override public String textLc() { return "bleu de France"; }
  }
  CAFE_NOIR {
    @Override public String textTc() { return "Café Noir"; }
  }
  RED,
  YELLOW,
  GREEN;

  // The text in title case
  private final String textTc;

  private Color() { 
    textTc = ucFirstLowerRest(this.toString());
  }

  // Title case
  public String textTc() { return textTc; }

  // For the middle of a sentence
  public String textLc() { return textTc().toLowerCase(); }

  // For the start of a sentence
  public String textUcFirst() {
    String lc = textLc();
    return lc.substring(0, 1).toUpperCase() + lc.substring(1);
  }
}

Il n'est pas si difficile de les utiliser correctement:

IllegalStateException(color1.textUcFirst() + " clashes horribly with " +
                      color2.textLc() + "!")

J'espère que cela démontre également pourquoi l'utilisation de valeurs d'énumération à casse mixte vous décevra également. Une dernière raison de conserver les majuscules avec des constantes d'énumération soulignées est que cela suit le principe du moindre étonnement. Les gens s'y attendent, donc si vous faites quelque chose de différent, vous devrez toujours vous expliquer ou traiter avec des gens qui utilisent votre code à mauvais escient.

3
GlenPeterson

On peut dire que le fait de suivre la convention de dénomination MAJUSCULE viole SEC . (Et YAGNI ). par exemple, dans votre exemple de code # 2: "RED" et "red" sont répétés.

Alors, suivez-vous la convention officielle ou suivez-vous DRY? Ton appel.

Dans mon code, je suivrai SEC. Cependant, je mettrai un commentaire sur la classe Enum, en disant "pas tous en majuscules parce que (explication ici)"

0
user949300

S'il y a la moindre chance que ces représentations de chaînes puissent être stockées dans des endroits tels que des bases de données ou des fichiers texte, les avoir liées aux constantes d'énumération réelles deviendra très problématique si vous avez besoin de refactoriser votre énumération.

Et si un jour vous décidiez de renommer Color.White à Color.TitaniumWhite alors qu'il existe des fichiers de données contenant "Blanc"?

De plus, une fois que vous aurez commencé à convertir des constantes enum en chaînes, l'étape suivante sera de générer des chaînes pour que l'utilisateur puisse les voir, et le problème ici est, comme vous le savez sûrement déjà, que la syntaxe de Java n'autorise pas les espaces dans les identifiants. (Vous n'aurez jamais Color.Titanium White.) Donc, comme vous aurez probablement besoin d'un mécanisme approprié pour générer des noms d'énumération à afficher à l'utilisateur, il est préférable d'éviter de compliquer inutilement votre énumération.

Cela dit, vous pouvez bien sûr aller de l'avant et faire ce que vous pensiez faire, puis refaçonner votre énumération plus tard, pour passer des noms au constructeur, quand (et si) vous rencontrez des problèmes.

Vous pouvez raser quelques lignes de votre énumération avec constructeur en déclarant le champ namepublic final et perdre le getter. (Quel est cet amour que les programmeurs Java ont envers les getters?)

0
Mike Nakis