Enum Java - pourquoi utiliser toString au lieu de name

171

Si vous regardez dans l'api enum la méthode, name()il est dit que:

Renvoie le nom de cette constante d'énumération, exactement comme déclaré dans sa déclaration d'énumération. La plupart des programmeurs devraient utiliser la méthode toString de préférence à celle-ci, car la méthode toString peut renvoyer un nom plus convivial. Cette méthode est conçue principalement pour une utilisation dans des situations spécialisées où l'exactitude dépend de l'obtention du nom exact, qui ne variera pas d'une version à l'autre.

Pourquoi est-il préférable d'utiliser toString()? Je veux dire que toString peut être remplacé lorsque name () est déjà final. Donc, si vous utilisez toString et que quelqu'un le remplace pour renvoyer une valeur codée en dur, toute votre application est en panne ... De plus, si vous regardez dans les sources, la méthode toString () renvoie exactement et juste le nom. C'est la même chose.

spauny
la source
4
Vous pouvez remplacer toString()votre énumération, mais personne d'autre ne peut l'étendre et la remplacer. Vous ne pouvez pas étendre les énumérations.
Erick

Réponses:

199

Cela dépend vraiment de ce que vous voulez faire avec la valeur renvoyée:

  • Si vous avez besoin d'obtenir le nom exact utilisé pour déclarer la constante enum, vous devez utiliser name()comme toStringpeut avoir été remplacé
  • Si vous souhaitez imprimer la constante enum d'une manière conviviale, vous devez utiliser celle toStringqui a peut-être été remplacée (ou non!).

Quand j'ai l'impression que cela peut prêter à confusion, je propose une getXXXméthode plus spécifique , par exemple:

public enum Fields {
    LAST_NAME("Last Name"), FIRST_NAME("First Name");

    private final String fieldDescription;

    private Fields(String value) {
        fieldDescription = value;
    }

    public String getFieldDescription() {
        return fieldDescription;
    }
}
assylies
la source
1
C'est acceptable. Bien que s'ils laissent enum avoir une classe de base, les choses seraient plus faciles.
ralphgabb
55

À utiliser name()lorsque vous souhaitez effectuer une comparaison ou utiliser la valeur codée en dur pour une utilisation interne dans votre code.

À utiliser toString()lorsque vous souhaitez présenter des informations à un utilisateur (y compris un développeur qui consulte un journal). Ne vous fiez jamais à votre code pour toString()donner une valeur spécifique. Ne le testez jamais par rapport à une chaîne spécifique. Si votre code est interrompu lorsque quelqu'un modifie correctement le toString()retour, cela signifie qu'il était déjà cassé.

Depuis le javadoc (c'est moi qui souligne):

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 doit être une représentation concise mais informative, facile à lire pour une personne . Il est recommandé que toutes les sous-classes remplacent cette méthode.

Denys Séguret
la source
23

name()est une méthode "intégrée" de enum. Il est définitif et vous ne pouvez pas modifier sa mise en œuvre. Il renvoie le nom de la constante enum tel qu'il est écrit, par exemple en majuscules, sans espaces, etc.

Comparez MOBILE_PHONE_NUMBERet Mobile phone number. Quelle version est la plus lisible? Je crois le second. C'est la différence: name()renvoie toujours MOBILE_PHONE_NUMBER, toString()peut être remplacé pour retourner Mobile phone number.

AlexR
la source
16
Ce n'est pas correct !! toString () renvoie Mobile phone numberuniquement si vous le remplacez pour renvoyer une telle valeur. Sinon, il reviendraMOBILE_PHONE_NUMBER
spauny
2
@spayny, il est évident que vous devez passer outre toString(). Le hic, c'est qu'il name()ne peut pas être annulé car il est définitif.
AlexR
13
@AlexR, vous devrez peut-être incorporer votre commentaire ci-dessus dans la réponse pour le rendre 100% correct
artfullyContrived
5
Je suis d'accord avec @artfullyContrived car ce n'était pas évident pour moi avant d'avoir lu vos commentaires.
martinatime
13

Alors que la plupart des gens suivent aveuglément les conseils du javadoc, il existe des situations très spécifiques dans lesquelles vous voulez réellement éviter toString (). Par exemple, j'utilise des énumérations dans mon code Java, mais elles doivent être sérialisées dans une base de données et inversement. Si j'utilisais toString (), je serais techniquement sujet au comportement remplacé comme d'autres l'ont souligné.

De plus, on peut également désérialiser de la base de données, par exemple, cela devrait toujours fonctionner en Java:

MyEnum taco = MyEnum.valueOf(MyEnum.TACO.name());

Alors que cela n'est pas garanti:

MyEnum taco = MyEnum.valueOf(MyEnum.TACO.toString());

Au fait, je trouve très étrange que le Javadoc dise explicitement "la plupart des programmeurs devraient". Je trouve très peu de cas d'utilisation dans la chaîne toString d'une énumération, si les gens l'utilisent pour un "nom convivial", c'est clairement un cas d'utilisation médiocre car ils devraient utiliser quelque chose de plus compatible avec i18n, ce qui, dans la plupart des cas, utilisez la méthode name ().

codage
la source
2
Merci de répondre. Cela fait presque 5 ans que j'ai posé cette question et je n'ai pas encore utilisé la méthode toString () pour une énumération! 99% des fois, j'utilise les énumérations exactement pour ce que vous avez décrit: la sérialisation et la désérialisation des noms d'énumérations vers / depuis la base de données.
spauny
5

Un exemple pratique où name () et toString () ont un sens pour être différents est un modèle où une énumération à valeur unique est utilisée pour définir un singleton. Cela semble surprenant au début, mais cela a beaucoup de sens:

enum SingletonComponent {
    INSTANCE(/*..configuration...*/);

    /* ...behavior... */

    @Override
    String toString() {
      return "SingletonComponent"; // better than default "INSTANCE"
    }
}

Dans ce cas:

SingletonComponent myComponent = SingletonComponent.INSTANCE;
assertThat(myComponent.name()).isEqualTo("INSTANCE"); // blah
assertThat(myComponent.toString()).isEqualTo("SingletonComponent"); // better
Marcin
la source
Ouais, vous avez raison ... un bon exemple est les prédicats d'énumération de la goyave
spauny
4

name () est littéralement le nom textuel dans le code java de l'énumération. Cela signifie qu'il est limité aux chaînes qui peuvent réellement apparaître dans votre code java, mais que toutes les chaînes souhaitables ne sont pas exprimables dans le code. Par exemple, vous pouvez avoir besoin d'une chaîne commençant par un nombre. name () ne pourra jamais obtenir cette chaîne pour vous.

Intropie
la source
-1

Vous pouvez également utiliser quelque chose comme le code ci-dessous. J'ai utilisé lombok pour éviter d'écrire certains des codes standard pour les getters et les constructeurs.

@AllArgsConstructor
@Getter
public enum RetroDeviceStatus {
    DELIVERED(0,"Delivered"),
    ACCEPTED(1, "Accepted"),
    REJECTED(2, "Rejected"),
    REPAIRED(3, "Repaired");

    private final Integer value;
    private final String stringValue;

    @Override
    public String toString() {
        return this.stringValue;
    }
}
Kamyar Miremadi
la source