Utilizzo dei valori Enum come valori letterali String


389

Qual è il modo migliore per usare i valori memorizzati in un Enum come valori letterali String? Per esempio:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3
}

Poi più tardi ho potuto utilizzare Mode.mode1per restituire la sua rappresentazione stringa come mode1. Senza dover continuare a chiamare Mode.mode1.toString().

Risposte:


646

Non puoi. Penso che tu abbia QUATTRO opzioni qui. Tutti e quattro offrono una soluzione ma con un approccio leggermente diverso ...

Opzione 1: utilizzare il built-in name()su un enum. Questo va perfettamente bene se non hai bisogno di alcun formato di denominazione speciale.

    String name = Modes.mode1.name(); // Returns the name of this enum constant, exactly as declared in its enum declaration.

Opzione due: aggiungi proprietà di override ai tuoi enumeri se vuoi un maggiore controllo

public enum Modes {
    mode1 ("Fancy Mode 1"),
    mode2 ("Fancy Mode 2"),
    mode3 ("Fancy Mode 3");

    private final String name;       

    private Modes(String s) {
        name = s;
    }

    public boolean equalsName(String otherName) {
        // (otherName == null) check is not needed because name.equals(null) returns false 
        return name.equals(otherName);
    }

    public String toString() {
       return this.name;
    }
}

Opzione tre: utilizzare finali statiche anziché enumerazioni:

public final class Modes {

    public static final String MODE_1 = "Fancy Mode 1";
    public static final String MODE_2 = "Fancy Mode 2";
    public static final String MODE_3 = "Fancy Mode 3";

    private Modes() { }
}

Opzione quattro: le interfacce hanno tutti i campi pubblico, statico e finale:

public interface Modes {

    String MODE_1 = "Fancy Mode 1";
    String MODE_2 = "Fancy Mode 2";
    String MODE_3 = "Fancy Mode 3";  
}

46
Questa risposta è in realtà errata: come puoi chiamare .name()Vedi: stackoverflow.com/a/6667365/887836
Alex

3
@ kato2 non corretto. Il metodo .name () viene creato automaticamente dal compilatore
Sean Patrick Floyd il

10
JavaDoc: String java.lang.Enum.name () Restituisce il nome di questa costante enum, esattamente come dichiarato nella sua dichiarazione enum. La maggior parte dei programmatori dovrebbe usare il metodo toString preferibilmente a questo, poiché il metodo toString potrebbe restituire un nome più user-friendly. Questo metodo è progettato principalmente per l'uso in situazioni specializzate in cui la correttezza dipende dall'ottenere il nome esatto, che non varierà da rilascio a rilascio. Restituisce: il nome di questa costante enum
SuperRetro

Il più grande di @Ryan Stewart richiede meno codice e meno codice == meno possibilità di bug
Eric

4
Non utilizzare le interfacce per contenere le costanti: Effective Java (3a edizione) consiglia di "utilizzare le interfacce solo per definire i tipi" (elemento 22).
Olivier Grégoire,

481

Ogni enum ha sia un metodo name () che valueOf (String). Il primo restituisce il nome della stringa dell'enum e il secondo fornisce il valore dell'enum il cui nome è la stringa. È come quello che stai cercando?

String name = Modes.mode1.name();
Modes mode = Modes.valueOf(name);

C'è anche un valore statico Of (Class, String) su Enum stesso, quindi puoi anche usarlo

Modes mode = Enum.valueOf(Modes.class, name);

50
QUESTA dovrebbe essere una RISPOSTA! L'uso di qualcosa come A ("A") può essere fonte di errori ed è un lavoro extra senza senso!
Firzen,

12
@Firzen no se il valore di stringa può contenere spazi o trattini, come nel caso some-really-long-string.
ceving

@ceving La domanda non è formulata bene per quanto riguarda spazi e trattini. Le domande mostrano un esempio sillabato, ma non chiedono come creare un Enum usando valori sillabati. Invece la domanda chiede come ottenere il valore String senza dover chiamare toString senza specificare i valori sillabati sono un requisito. Detto questo, penso che questa potrebbe essere una risposta migliore se fosse modificata per menzionare che i valori di Enum devono ancora seguire le regole di denominazione Java e dovrebbero usare qualcosa menzionato nella risposta accettata se tali caratteri fossero richiesti.
Hazok,

Volevo aggiungere un link a mkyong che utilizza il valueOf(String)metodo in combinazione con toUpperCase(Locale)per garantire la conversione di stringhe.
ID sconosciuto

2
Il motivo per cui molte persone preferiscono l'approccio alla proprietà su Enum.name () è che la logica basata su Enum.name () è quindi per sempre in balia dei nomi dei valori. Se il codice cambia in futuro, questo potrebbe trasformarsi in un problema non banale per aggirare poiché tutta la logica precedente si interromperà sulle modifiche al set di valori Enum. La sostituzione e l'utilizzo dell'approccio toString () consente allo sviluppatore di avere un maggiore controllo sui valori in uso, inclusi la duplicazione, i caratteri dei nomi delle variabili non validi ecc. Non dimenticare di ignorare anche valueOf ().
indivisibile

79

È possibile ignorare il toString()metodo per ciascun valore enum.

Esempio:

public enum Country {

  DE {
    @Override
    public String toString() {
      return "Germany";
    }
  },
  IT {
    @Override
    public String toString() {
      return "Italy";
    }
  },
  US {
    @Override
    public String toString() {
      return "United States";
    }
  }

}

Uso:

public static void main(String[] args) {
  System.out.println(Country.DE); // Germany
  System.out.println(Country.IT); // Italy
  System.out.println(Country.US); // United States
}

2
Mi piace questo. Nessun motivo per non usare un enum come classe con ulteriori funzionalità come ottenere un elenco di tutti i valori, ottenere una stringa di ogni tipo, ecc.
Diegosasw

8
Brutto e non riutilizzabile. Molto meglio fornire un valore stringa come costruttore per Country e quindi sovrascrivere il metodo toString () per l'enum.
greg7gkb,

4
Questa è una buona tecnica quando hai una numerazione abbastanza grande e vuoi solo sovrascrivere ciò che le cose stampano come per uno o due membri.
Donal Fellows,

3
Questo non si ridimensiona affatto. Non farlo
sebnukem,

1
Questo ha senso per me
hanzolo,

35

Come menziona Benny Neugebauer, potresti sovrascrivere toString (). Tuttavia, invece di sovrascrivere il toString per ogni campo enum mi piace di più qualcosa del genere:

public enum Country{
    SPAIN("España"),
    ITALY("Italia"),
    PORTUGAL("Portugal");


    private String value;

    Country(final String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

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

È inoltre possibile aggiungere un metodo statico per recuperare tutti i campi, per stamparli tutti, ecc. È sufficiente chiamare getValue per ottenere la stringa associata a ciascun elemento Enum



21
public enum Modes {
  MODE1("Mode1"),
  MODE2("Mode2"),
  MODE3("Mode3");

 private String value;
 public String getValue() {
    return value;
   }
 private Modes(String value) {
  this.value = value;
 } 
}

è possibile effettuare una chiamata come di seguito ovunque si desideri ottenere il valore come stringa dall'enum.

Modes.MODE1.getvalue();

Ciò restituirà "Mode1" come una stringa.


6

Puoi usare Mode.mode1.name()comunque spesso non è necessario farlo.

Mode mode =
System.out.println("The mode is "+mode);

6
Vale la pena notare che l'operatore + chiamerà toString () sull'enum e non name (). E toString () può essere sostituito per restituire qualcosa di diverso dal nome (anche se non è desiderabile)
JB Nizet,

1
Entrambi name()e toString()possono essere sostituiti, ma si spera enumche ciò risulti chiaro dalla lettura del codice se ciò accade.
Peter Lawrey,

9
No. name () è definitivo e restituisce sempre il nome dell'enum come dichiarato nella sua dichiarazione enum.
JB Nizet,

1
@JB Nizet, hai ragione. name()lo è final. Grazie per avermi corretto. :)
Peter Lawrey,

6

Per quanto ne so, l'unico modo per ottenere il nome sarebbe

Mode.mode1.name();

Se ne hai davvero bisogno in questo modo, tuttavia, potresti fare:

public enum Modes {
    mode1 ("Mode1"),
    mode2 ("Mode2"),
    mode3 ("Mode3");

    private String name;       

    private Modes(String s) {
        name = s;
    }
}

1
Ma in questo caso, non Mode.mode1è ancora di tipo String.
Larry,

Oh giusto. Avresti bisogno di un metodo getName (), che tipo di sconfigge lo scopo, quindi no, non puoi farlo.
Jake Roussel,

"name" è un nome di campo errato, è un campo standard di enum.
Wooff,

6

Per i miei enum non mi piace pensare che siano assegnati con 1 stringa ciascuno. Questo è il modo in cui implemento un metodo toString () su enums.

enum Animal
{
    DOG, CAT, BIRD;
    public String toString(){
        switch (this) {
            case DOG: return "Dog";
            case CAT: return "Cat";
            case BIRD: return "Bird";
        }
        return null;
    }
}

1
Lanciare un'eccezione di runtime sarebbe meglio invece di restituire null poiché dovrebbe essere un codice non raggiungibile?
affitta

Il returnè ridondante, perché accendere enumerazioni con tutti enumerazioni si termina.
Danon,

5

Puoi semplicemente usare:

""+ Modes.mode1

Non ne sono sicuro al 100% ma, per quanto ne so, questo cast non è necessario, vero? Concatenare una stringa vuota con un'altra variabile dovrebbe richiedere automaticamente una conversione o ci sono eccezioni a questa regola?
ID sconosciuto

1
Hai ragione, dovrebbe essere la versione corretta "" + Modes.mode1. Ho corretto la risposta
Buddy,

La risposta di EB beneficia anche di ricordare il linguaggio dei pitoni ''.join()
androide antropico

5

la mia soluzione per il tuo problema!

import java.util.HashMap;
import java.util.Map;

public enum MapEnumSample {
    Mustang("One of the fastest cars in the world!"), 
    Mercedes("One of the most beautiful cars in the world!"), 
    Ferrari("Ferrari or Mercedes, which one is the best?");

    private final String description;
    private static Map<String, String> enumMap;

    private MapEnumSample(String description) {
        this.description = description;
    }

    public String getEnumValue() {
        return description;
    }

    public static String getEnumKey(String name) {
        if (enumMap == null) {
            initializeMap();
        }
        return enumMap.get(name);
    }

    private static Map<String, String> initializeMap() {
        enumMap = new HashMap<String, String>();
        for (MapEnumSample access : MapEnumSample.values()) {
            enumMap.put(access.getEnumValue(), access.toString());
        }
        return enumMap;
    }

    public static void main(String[] args) {

        // getting value from Description
        System.out.println(MapEnumSample.getEnumKey("One of the fastest cars in the world!"));

        // getting value from Constant
        System.out.println(MapEnumSample.Mustang.getEnumValue());

        System.out.println(MapEnumSample.getEnumKey("One of the most beautiful cars in the world!"));
        System.out.println(MapEnumSample.Mercedes.getEnumValue());

        // doesnt exist in Enum
        System.out.println("Mustang or Mercedes, which one is the best?");
        System.out.println(MapEnumSample.getEnumKey("Mustang or Mercedes, which one is the best?") == null ? "I don't know!" : "I believe that "
                + MapEnumSample.getEnumKey("Ferrari or Mustang, which one is the best?") + " is the best!.");

        // exists in Enum
        System.out.println("Ferrari or Mercedes, wich one is the best?");
        System.out.println(MapEnumSample.getEnumKey("Ferrari or Mercedes, which one is the best?") == null ? "I don't know!" : "I believe that "
                + MapEnumSample.getEnumKey("Ferrari or Mercedes, which one is the best?") + " is the best!");

    }
}

Sembra che il problema del PO sia stato risolto 4 anni fa, ma benvenuto su StackOverflow :)
TDG

1
Grazie, solo per aiutare qualcuno come me, alla ricerca di risposte più obiettive a vecchi problemi :)
Renan Galdino da Silva

3

Enum è solo un po 'di classe speciale. Enum può memorizzare campi aggiuntivi, implementare metodi ecc. Ad esempio

public enum Modes {
    mode1('a'),
    mode2('b'),
    mode3('c'),
    ;
    char c;

    private Modes(char c) {
        this.c = c;
    }
    public char character() {
        return c;
    }
}

Ora puoi dire:

System.out.println(Modes.mode1.character())

e vedi l'output: a


3
package com.common.test;

public  enum Days {


    monday(1,"Monday"),tuesday(2,"Tuesday"),wednesday(3,"Wednesday"),
    thrusday(4,"Thrusday"),friday(5,"Friday"),saturday(6,"Saturday"),sunday(7,"Sunday");

    private int id;
    private String desc;


    Days(int id,String desc){
        this.id=id;
        this.desc=desc;
    }

    public static String getDay(int id){

        for (Days day : Days.values()) {
            if (day.getId() == id) {
                return day.getDesc();
            }
        }
        return null;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }



};

1
Puoi spiegare come risolverebbe il problema?
Phani,

puoi chiamare questo enum ovunque usando questa linea: int id = 1; String dayName = Days.getDay (id); , passa qui id. restituirà la descrizione per

2

Questo metodo dovrebbe funzionare con qualsiasi enum :

public enum MyEnum {
    VALUE1,
    VALUE2,
    VALUE3;

    public int getValue() {
        return this.ordinal();
    }

    public static DataType forValue(int value) {
        return values()[value];
    }

    public String toString() {
        return forValue(getValue()).name();
    }
}

2
public enum Environment
{
    PROD("https://prod.domain.com:1088/"),
    SIT("https://sit.domain.com:2019/"),
    CIT("https://cit.domain.com:8080/"),
    DEV("https://dev.domain.com:21323/");

    private String url;

    Environment(String envUrl) {
        this.url = envUrl;
    }

    public String getUrl() {
        return url;
    }
}

String prodUrl = Environment.PROD.getUrl();

Stampa:

https://prod.domain.com:1088/

Questo disegno per costanti di stringa enum funziona nella maggior parte dei casi.


0

dopo molti tentativi sono arrivato con questa soluzione

public static enum Operation {

    Addition, Subtraction, Multiplication, Division,;

    public String getUserFriendlyString() {
        if (this==Addition) {
            return " + ";
        } else if (this==Subtraction) {
            return " - ";
        } else if (this==Multiplication) {
            return " * ";
        } else if (this==Division) {
            return " / ";
        }
        return "undefined";
       }
}

0

Puoi provare questo:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3;

    public String toString(){
        switch(this) {
            case some-really-long-string:
                return "some-really-long-string";
            case mode2:
                return "mode2";
            default: return "undefined";
        }
    }

}


0

ho trovato questo è più facile per prevenire errori di tipo:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3;

    String str;

    Modes(){
        this.str = super.name();
    }

    @Override
    @NonNull
    public String toString() {
        return str;
    }

tuttavia, ciò può funzionare quando è necessario utilizzare una stringa su un log / println o quando java compila automaticamente il metodo toString (), ma su una riga di codice come questa ->

// sample method that require (string,value)
intent.putExtra(Modes.mode1 ,shareElement.getMode()); // java error
// first argument enum does not return value

invece, come detto sopra, dovrai comunque estendere l'enum e utilizzarlo .name() in questi casi come questo:

intent.putExtra(Modes.mode1.name() ,shareElement.getMode()); 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.