Verwenden von Enum-Werten als String-Literale

389

Was ist der beste Weg, um die in einer Aufzählung gespeicherten Werte als String-Literale zu verwenden? Zum Beispiel:

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

Dann später könnte ich verwenden Mode.mode1, um seine Zeichenfolgendarstellung als zurückzugeben mode1. Ohne weiter anrufen zu müssen Mode.mode1.toString().

Larry
quelle

Antworten:

646

Das kannst du nicht. Ich denke, Sie haben hier VIER Optionen. Alle vier bieten eine Lösung, aber mit einem etwas anderen Ansatz ...

Option Eins: Verwenden Sie die in name()einer Aufzählung integrierte Funktion. Dies ist vollkommen in Ordnung, wenn Sie kein spezielles Namensformat benötigen.

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

Option 2: Fügen Sie Ihren Aufzählungen übergeordnete Eigenschaften hinzu, wenn Sie mehr Kontrolle wünschen

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;
    }
}

Option 3: Verwenden Sie statische Finals anstelle von Aufzählungen:

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() { }
}

Option 4: Schnittstellen haben jedes Feld öffentlich, statisch und endgültig:

public interface Modes {

    String MODE_1 = "Fancy Mode 1";
    String MODE_2 = "Fancy Mode 2";
    String MODE_3 = "Fancy Mode 3";  
}
Michael J. Lee
quelle
46
Diese Antwort ist in der Tat falsch: wie Sie anrufen können .name()Siehe: stackoverflow.com/a/6667365/887836
Alex
3
@ kato2 nicht korrekt. Die .name () -Methode wird automatisch vom Compiler erstellt
Sean Patrick Floyd
10
JavaDoc: String java.lang.Enum.name () Gibt den Namen dieser Aufzählungskonstante genau so zurück, wie er in seiner Aufzählungsdeklaration deklariert ist. Die meisten Programmierer sollten die toString-Methode dieser vorziehen, da die toString-Methode möglicherweise einen benutzerfreundlicheren Namen zurückgibt. Diese Methode wurde hauptsächlich für den Einsatz in speziellen Situationen entwickelt, in denen die Richtigkeit davon abhängt, den genauen Namen zu erhalten, der von Version zu Version nicht variiert. Rückgabe: der Name dieser Enum-Konstante
SuperRetro
Das awser von @Ryan Stewart benötigt weniger Code und weniger Code == weniger Wahrscheinlichkeit von Fehlern
Eric
4
Verwenden Sie keine Schnittstellen, um Konstanten zu speichern: Effektives Java (3. Ausgabe) empfiehlt, "Schnittstellen nur zum Definieren von Typen zu verwenden" (Punkt 22).
Olivier Grégoire
481

Jede Aufzählung hat sowohl eine name () - als auch eine valueOf (String) -Methode. Ersteres gibt den Zeichenfolgennamen der Aufzählung zurück, und letzteres gibt den Aufzählungswert an, dessen Name die Zeichenfolge ist. Ist das wie das, wonach Sie suchen?

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

Es gibt auch einen statischen valueOf (Class, String) in Enum selbst, den Sie auch verwenden können

Modes mode = Enum.valueOf(Modes.class, name);
Ryan Stewart
quelle
50
Dies sollte eine Antwort sein! Die Verwendung von A ("A") kann zu Fehlern führen und ist sinnlose zusätzliche Arbeit!
Firzen
12
@Firzen nicht, wenn der Zeichenfolgenwert Leerzeichen oder Bindestriche enthalten darf, was in der Fall ist some-really-long-string.
Ceving
@ceving Die Frage ist in Bezug auf Leerzeichen und Bindestriche nicht gut formuliert. Die Fragen zeigen ein Beispiel mit Bindestrich, fragen jedoch nicht, wie eine Aufzählung mit Bindestrichwerten erstellt werden soll. Stattdessen wird gefragt, wie der String-Wert abgerufen werden kann, ohne dass toString aufgerufen werden muss, ohne dass getrennte Werte angegeben werden müssen. Ich denke jedoch, dass dies eine bessere Antwort sein könnte, wenn geändert würde, um zu erwähnen, dass die Enum-Werte weiterhin den Java-Namensregeln entsprechen müssen und etwas verwenden müssten, das in der akzeptierten Antwort erwähnt wird, wenn solche Zeichen erforderlich wären.
Hazok
Ich wollte einen Link zu mkyong hinzufügen, der die valueOf(String)Methode in Kombination mit verwendet toUpperCase(Locale), um die String-Konvertierung sicherzustellen.
Unbekannte
2
Der Grund, warum viele Leute den Eigenschaftsansatz Enum.name () vorziehen, ist, dass die auf Enum.name () basierende Logik dann für immer den Wertnamen ausgeliefert ist. Wenn sich der Code in Zukunft ändert, kann dies zu einem nicht trivialen Problem werden, da die gesamte vorherige Logik bei Änderungen am Enum-Wertesatz unterbrochen wird. Durch Überschreiben und Verwenden des toString () -Ansatzes hat der Entwickler eine bessere Kontrolle über die verwendeten Werte, einschließlich Duplizierung, ungültiger Variablennamenzeichen usw. Vergessen Sie nicht, auch valueOf () zu überschreiben.
unteilbar
79

Sie könnten das überschreiben toString() Methode für jeden Aufzählungswert .

Beispiel:

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";
    }
  }

}

Verwendungszweck:

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
}
Benny Neugebauer
quelle
2
Ich mag das. Kein Grund, eine Aufzählung nicht als Klasse mit weiteren Funktionen zu verwenden, z. B. eine Liste aller Werte
abzurufen
8
Hässlich und nicht wiederverwendbar. Es ist viel besser, einen Zeichenfolgenwert als Konstruktor für Country anzugeben und dann die toString () -Methode für die Aufzählung zu überschreiben.
Greg7gkb
4
Dies ist eine gute Technik, wenn Sie eine ziemlich große Aufzählung haben und nur überschreiben möchten, wie die Dinge für ein oder zwei Mitglieder gedruckt werden.
Donal Fellows
3
Dies skaliert überhaupt nicht. Tu das nicht.
sebnukem
1
Das macht Sinn für mich
Hanzolo
35

Wie Benny Neugebauer erwähnt, könnten Sie den toString () überschreiben. Anstatt jedoch den toString für jedes Enum-Feld zu überschreiben, gefällt mir eher Folgendes:

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();
    }
}

Sie können auch eine statische Methode hinzufügen, um alle Felder abzurufen, alle zu drucken usw. Rufen Sie einfach getValue auf, um die Zeichenfolge zu erhalten, die jedem Enum-Element zugeordnet ist

diegosasw
quelle
30

mode1.name()oder String.valueOf(mode1). Besser geht es leider nicht

Sean Patrick Floyd
quelle
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;
 } 
}

Sie können einen Aufruf wie unten ausführen, wo immer Sie den Wert als Zeichenfolge aus der Aufzählung erhalten möchten.

Modes.MODE1.getvalue();

Dies gibt "Mode1" als String zurück.

vamsi
quelle
6

Sie können verwenden Mode.mode1.name(), müssen dies jedoch häufig nicht tun.

Mode mode =
System.out.println("The mode is "+mode);
Peter Lawrey
quelle
6
Es ist erwähnenswert, dass der Operator + in der Enumeration toString () und nicht name () aufruft. Und toString () kann überschrieben werden, um etwas anderes als den Namen zurückzugeben (auch wenn es nicht wünschenswert ist)
JB Nizet
1
Beides name()und toString()kann überschrieben werden, aber hoffentlich wird dies durch das Lesen des Codes für das, enumwenn dies geschieht , klar .
Peter Lawrey
9
Nr. Name () ist endgültig und gibt immer den Namen der Aufzählung zurück, wie in der Aufzählungserklärung angegeben.
JB Nizet
1
@JB Nizet, du hast recht. name()ist final. Danke, dass du mich korrigiert hast. :)
Peter Lawrey
6

Soweit ich weiß, wäre der einzige Weg, den Namen zu bekommen, der

Mode.mode1.name();

Wenn Sie es jedoch wirklich so brauchen, können Sie Folgendes tun:

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

    private String name;       

    private Modes(String s) {
        name = s;
    }
}
Jake Roussel
quelle
1
Aber in diesem Fall Mode.mode1ist immer noch nicht vom Typ String.
Larry
Oh, richtig. Sie benötigen eine getName () -Methode, die den Zweck zunichte macht. Nein, das können Sie nicht.
Jake Roussel
"name" ist ein schlechter Feldname, es ist ein Standardfeld von enum.
Wooff
6

Für meine Enums denke ich nicht wirklich gerne daran, dass ihnen jeweils 1 String zugewiesen wird. So implementiere ich eine toString () -Methode für 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;
    }
}
Ethan
quelle
1
Das Auslösen einer Laufzeitausnahme wäre besser, als null zurückzugeben, da es sich um nicht erreichbaren Code handeln sollte.
Mieten
Das returnist redundant, da das Einschalten von Enums mit allen Enums beendet wird.
Danon
5

Sie können einfach verwenden:

""+ Modes.mode1
Kumpel
quelle
Ich bin mir da nicht 100% sicher, aber meines Wissens ist diese Besetzung nicht notwendig, oder? Das Verketten einer leeren Zeichenfolge mit einer anderen Variablen sollte automatisch eine Konvertierung erfordern, oder gibt es Ausnahmen von dieser Regel?
Unbekannte
1
Sie haben Recht, die richtige Version sollte sein "" + Modes.mode1. Ich habe die Antwort korrigiert
Buddy
EBs Antwort profitiert auch davon, dass sie an die Python-Redewendung erinnert ''.join()
anthropischer Android
5

meine Lösung für Ihr Problem!

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!");

    }
}
Renan Galdino da Silva
quelle
Es sieht so aus, als ob das Problem des OP vor 4 Jahren gelöst wurde, aber willkommen bei StackOverflow :)
TDG
1
Danke, nur um jemandem wie mir zu helfen, der nach objektiveren Antworten auf alte Probleme sucht :)
Renan Galdino da Silva
3

Enum ist nur eine kleine Sonderklasse. Aufzählungen können zusätzliche Felder speichern, Methoden implementieren usw. Zum Beispiel

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

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

Jetzt können Sie sagen:

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

und siehe Ausgabe: a

AlexR
quelle
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;
    }



};

quelle
1
Können Sie bitte erklären, wie es das Problem lösen würde?
Phani
Sie können diese Aufzählung überall mit dieser Zeile aufrufen: int id = 1; String dayName = Days.getDay (id); , hier übergeben id. es wird Beschreibung für diese ID zurückgeben, die "Dienstag" ist
2

Diese Methode sollte mit folgenden Methoden funktionieren 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();
    }
}
Caner
quelle
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();

Es wird gedruckt:

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

Dieses Design für Enum-String-Konstanten funktioniert in den meisten Fällen.

lokesh
quelle
0

Nach vielen Versuchen bin ich mit dieser Lösung gekommen

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";
       }
}
Basheer AL-MOMANI
quelle
0

Sie können dies versuchen:

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";
        }
    }

}}

Kamil Naja
quelle
0

Ich fand, dass dies einfacher ist, um Typfehler zu verhindern:

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

    String str;

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

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

Dies kann jedoch funktionieren, wenn Sie einen String für ein Protokoll / einen Druck verwenden müssen oder wenn Java die toString () -Methode automatisch kompiliert, jedoch für eine Codezeile wie diese ->

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

Stattdessen müssen Sie, wie oben erwähnt, die Aufzählung noch erweitern und .name() in folgenden Fällen verwenden:

intent.putExtra(Modes.mode1.name() ,shareElement.getMode()); 
ItzikH
quelle