141 votes

Remplacer valueof() et toString() dans un enum Java

Les valeurs de mon enum sont des mots qui doivent avoir des espaces, mais les enums ne peuvent pas avoir d'espaces dans leurs valeurs, donc tout est mélangé. Je veux remplacer toString() pour ajouter ces espaces là où je lui dis de le faire.

Je veux aussi que l'enum fournisse le bon enum lorsque j'utilise valueOf() sur la même chaîne que celle à laquelle j'ai ajouté les espaces.

Par exemple :

public enum RandomEnum
{
     StartHere,
     StopHere
}

Appelez toString() sur RandomEnum dont la valeur est StartHere renvoie une chaîne "Start Here" . Appelez valueof() sur cette même chaîne ( "Start Here" ) renvoie la valeur de l'enum StartHere .

Comment puis-je le faire ?

2 votes

Ajoutez la balise "Java" pour obtenir plus de commentaires/réponses.

0 votes

226voto

Jugal Shah Points 1367

Vous pouvez essayer ce code. Puisque vous ne pouvez pas remplacer valueOf vous devez définir une méthode personnalisée ( getEnum dans l'exemple de code ci-dessous) qui renvoie la valeur dont vous avez besoin et modifiez votre client pour utiliser cette méthode à la place.

public enum RandomEnum {

    StartHere("Start Here"),
    StopHere("Stop Here");

    private String value;

    RandomEnum(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    @Override
    public String toString() {
        return this.getValue();
    }

    public static RandomEnum getEnum(String value) {
        for(RandomEnum v : values())
            if(v.getValue().equalsIgnoreCase(value)) return v;
        throw new IllegalArgumentException();
    }
}

4 votes

GetEnum pourrait être raccourci si vous faites ce qui suit : v.getValue().equals(value) ; la vérification de la nullité peut être omise.

0 votes

Vous pouvez également construire paresseusement une carte et la réutiliser, mais faites attention aux problèmes de threading lors de sa construction.

25 votes

Ne fonctionne pas dans les scénarios où vous ne pouvez pas changer l'appel de la méthode valueOf() en getValue(), par exemple lorsque vous définissez certains champs via des annotations Hibernate pour qu'ils correspondent à des valeurs d'enum.

22voto

Bat Points 11

Essayez ceci, mais je ne suis pas sûr que ça marchera partout :)

public enum MyEnum {
    A("Start There"),
    B("Start Here");

    MyEnum(String name) {
        try {
            Field fieldName = getClass().getSuperclass().getDeclaredField("name");
            fieldName.setAccessible(true);
            fieldName.set(this, name);
            fieldName.setAccessible(false);
        } catch (Exception e) {}
    }
}

20 votes

Pourquoi suis-je le seul à qui ce genre de choses semble diabolique ? Je veux dire que ça a l'air vraiment cool mais quelqu'un qui n'a pas de contexte et qui lit ce code se dirait probablement "WTF ?".

16 votes

@NicolasGuillaume C'est le genre de code qui, s'il était implémenté, aurait désespérément besoin d'un commentaire expliquant pourquoi il est là et quel problème le programmeur a essayé de résoudre. :-)

12 votes

N'attrapez pas d'exception générique, car il peut s'agir d'une erreur de mémoire ou d'une erreur d'écriture. tout ce qui est

15voto

pedorro Points 569

Vous pouvez utiliser une carte statique dans votre enum qui fait correspondre les chaînes de caractères aux constantes de l'enum. Utilisez-la dans une méthode statique 'getEnum'. Ainsi, il n'est pas nécessaire d'itérer à travers les enums chaque fois que vous voulez en obtenir un à partir de sa valeur String.

public enum RandomEnum {

    StartHere("Start Here"),
    StopHere("Stop Here");

    private final String strVal;
    private RandomEnum(String strVal) {
        this.strVal = strVal;
    }

    public static RandomEnum getEnum(String strVal) {
        if(!strValMap.containsKey(strVal)) {
            throw new IllegalArgumentException("Unknown String Value: " + strVal);
        }
        return strValMap.get(strVal);
    }

    private static final Map<String, RandomEnum> strValMap;
    static {
        final Map<String, RandomEnum> tmpMap = Maps.newHashMap();
        for(final RandomEnum en : RandomEnum.values()) {
            tmpMap.put(en.strVal, en);
        }
        strValMap = ImmutableMap.copyOf(tmpMap);
    }

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

Assurez-vous simplement que l'initialisation statique de la carte a lieu après la déclaration des constantes de l'enum.

À propos, le type " ImmutableMap " provient de l'API Google Guava et je le recommande vivement dans des cas comme celui-ci.


EDIT - Selon les commentaires :

  1. Cette solution suppose que chaque valeur de chaîne attribuée est unique et non nulle. Étant donné que le créateur de l'enum peut contrôler cela, et que la chaîne de caractères correspond à la valeur unique et non nulle de l'enum, cela semble être une restriction sûre.
  2. J'ai ajouté la méthode "toSTring()" comme demandé dans la question.

1 votes

J'ai reçu quelques votes négatifs sur cette réponse. Quelqu'un peut-il expliquer pourquoi cette réponse est mauvaise ? Je suis simplement curieux de savoir ce que les gens pensent.

1 votes

Cela échouera pour le scénario ayant multiple les constantes d'énumération avec la même 'valeur' comme RestartHere("replay"), ReplayHere("replay") ou pas de "valeur" du tout, comme PauseHere, WaitHere (c'est-à-dire qu'un enum a un constructeur par défaut du type private RandomEnum() { this.strVal = null; }

1 votes

Vous devez utiliser ImmutableMap.Builder au lieu de créer une MutableMap pour construire + ImmutableMap::copyOf.

2voto

Java42 Points 4375

Je ne pense pas que valueOf("Start Here") va fonctionner. Mais pour ce qui est des espaces... essayez ce qui suit...

static private enum RandomEnum {
    R("Start There"), 
    G("Start Here"); 
    String value;
    RandomEnum(String s) {
        value = s;
    }
}

System.out.println(RandomEnum.G.value);
System.out.println(RandomEnum.valueOf("G").value);

Start Here
Start Here

2voto

exception Points 315

Ce qui suit est une belle alternative générique à valueOf()

public static RandomEnum getEnum(String value) {
  for (RandomEnum re : RandomEnum.values()) {
    if (re.description.compareTo(value) == 0) {
      return re;
    }
  }
  throw new IllegalArgumentException("Invalid RandomEnum value: " + value);
}

0 votes

Est l'utilisation de compareTo() plus élégant que equals() pour les cordes ?

0 votes

L'élégance n'est pas un problème - je suis d'accord pour dire que .equals() fonctionnerait bien. On pourrait utiliser == si vous aimez. (Bien qu'une bonne raison de ne pas le faire soit que vous remplaciez un jour l'enum par une classe).

4 votes

N'UTILISEZ JAMAIS == pour les comparaisons de chaînes de caractères car il vérifiera l'égalité des objets alors que vous avez besoin de vérifier l'égalité du contenu. Pour cela, utilisez la méthode equals() de la classe String.

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