Java-Enumeration - warum toString anstelle von name verwenden?

171

Wenn Sie sich in der Enum-API die Methode ansehen name(), heißt es:

Gibt den Namen dieser Aufzählungskonstante genau so zurück, wie er in der Aufzählungsdeklaration deklariert ist. Die meisten Programmierer sollten die toString-Methode gegenüber dieser bevorzugen, 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.

Warum ist es besser zu benutzen toString()? Ich meine, toString kann überschrieben werden, wenn name () bereits endgültig ist. Wenn Sie also toString verwenden und jemand es überschreibt, um einen fest codierten Wert zurückzugeben, ist Ihre gesamte Anwendung ausgefallen ... Auch wenn Sie in den Quellen nachsehen, gibt die toString () -Methode genau und nur den Namen zurück. Das ist gleich.

spauny
quelle
4
Sie können toString()Ihre Aufzählung überschreiben , aber niemand anderes kann sie erweitern und überschreiben. Sie können keine Aufzählungen verlängern.
Erick G. Hagstrom

Antworten:

198

Es hängt wirklich davon ab, was Sie mit dem zurückgegebenen Wert tun möchten:

  • Wenn Sie den genauen Namen bekommen müssen verwendet , um die Enumeration Konstante zu erklären, sollten Sie name()als toStringmöglicherweise überschriebenen gewesen sein
  • Wenn Sie die Enum-Konstante benutzerfreundlich drucken möchten, sollten Sie die verwenden, toStringdie möglicherweise überschrieben wurde (oder nicht!).

Wenn ich das Gefühl habe, dass es verwirrend sein könnte, biete ich eine spezifischere getXXXMethode an, zum Beispiel:

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;
    }
}
Assylien
quelle
1
Das ist akzeptabel. Obwohl, wenn sie Enum eine Basisklasse haben lassen, die Dinge einfacher wären.
Ralphgabb
55

Verwenden name()Sie diese Option, wenn Sie einen Vergleich durchführen oder den fest codierten Wert für eine interne Verwendung in Ihrem Code verwenden möchten.

Verwenden toString()Sie diese Option, wenn Sie einem Benutzer Informationen präsentieren möchten (einschließlich eines Entwicklers, der ein Protokoll betrachtet). Verlassen Sie sich in Ihrem Code niemals darauf toString(), einen bestimmten Wert anzugeben. Testen Sie es niemals gegen eine bestimmte Saite. Wenn Ihr Code beschädigt wird, wenn jemand die toString()Rückgabe korrekt ändert , war er bereits fehlerhaft.

Aus dem Javadoc (Schwerpunkt Mine):

Gibt eine Zeichenfolgendarstellung des Objekts zurück. Im Allgemeinen gibt die toString-Methode eine Zeichenfolge zurück, die dieses Objekt "textuell darstellt" . Das Ergebnis sollte eine präzise, ​​aber informative Darstellung sein, die für eine Person leicht zu lesen ist . Es wird empfohlen, dass alle Unterklassen diese Methode überschreiben.

Denys Séguret
quelle
23

name()ist eine "eingebaute" Methode von enum. Es ist endgültig und Sie können seine Implementierung nicht ändern. Es gibt den Namen der Enum-Konstante zurück, wie er geschrieben ist, z. B. in Großbuchstaben, ohne Leerzeichen usw.

Vergleiche MOBILE_PHONE_NUMBERund Mobile phone number. Welche Version ist besser lesbar? Ich glaube der zweite. Dies ist der Unterschied: name()Immer zurück MOBILE_PHONE_NUMBER, toString()kann überschrieben werden, um zurückzukehren Mobile phone number.

AlexR
quelle
16
Das ist nicht richtig!! toString () gibt Mobile phone numbernur zurück, wenn Sie es überschreiben, um einen solchen Wert zurückzugeben. Andernfalls wird es zurückkehrenMOBILE_PHONE_NUMBER
spauny
2
@spayny, es ist offensichtlich, dass Sie überschreiben müssen toString(). Der Haken ist, dass name()nicht überschrieben werden kann, da es endgültig ist.
AlexR
13
@AlexR Sie müssen möglicherweise Ihren obigen Kommentar in die Antwort aufnehmen, um es 100% korrekt zu machen
kunstvoll
5
Ich stimme @artfullyContrived zu, da es mir nicht klar war, bis ich Ihre Kommentare gelesen habe.
Martinatime
13

Während die meisten Menschen blind den Ratschlägen des Javadoc folgen, gibt es sehr spezielle Situationen, in denen Sie toString () tatsächlich vermeiden möchten. Zum Beispiel verwende ich Enums in meinem Java-Code, aber sie müssen in eine Datenbank serialisiert und wieder zurück. Wenn ich toString () verwenden würde, würde ich technisch dazu neigen, das überschriebene Verhalten zu erhalten, wie andere darauf hingewiesen haben.

Zusätzlich kann man auch aus der Datenbank de-serialisieren, dies sollte beispielsweise immer in Java funktionieren:

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

Dies ist jedoch nicht garantiert:

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

Übrigens finde ich es sehr seltsam für den Javadoc, explizit zu sagen, "die meisten Programmierer sollten". Ich finde sehr wenig Anwendungsfälle im toString einer Aufzählung, wenn Leute das für einen "freundlichen Namen" verwenden, ist dies eindeutig ein schlechter Anwendungsfall, da sie etwas verwenden sollten, das mit i18n kompatibler ist, was in den meisten Fällen der Fall wäre. Verwenden Sie die Methode name ().

Codierung
quelle
2
Danke für die Antwort. Es ist fast 5 Jahre her, seit ich diese Frage gestellt habe und ich habe die toString () -Methode noch nicht für eine Aufzählung verwendet! In 99% der Fälle verwende ich Enums genau für das, was Sie beschrieben haben: Serialisieren und Deserialisieren von Enum-Namen zur / von der Datenbank.
spauny
5

Ein praktisches Beispiel, wenn name () und toString () sinnvoll sind, um sich zu unterscheiden, ist ein Muster, bei dem einwertige Aufzählung zum Definieren eines Singletons verwendet wird. Es sieht auf den ersten Blick überraschend aus, macht aber sehr viel Sinn:

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

    /* ...behavior... */

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

In diesem Fall:

SingletonComponent myComponent = SingletonComponent.INSTANCE;
assertThat(myComponent.name()).isEqualTo("INSTANCE"); // blah
assertThat(myComponent.toString()).isEqualTo("SingletonComponent"); // better
Marcin
quelle
Ja, Sie haben Recht ... ein gutes Beispiel ist die Aufzählung Prädikate der Guave
spauny
4

name () ist buchstäblich der Textname im Java-Code der Aufzählung. Das bedeutet, dass es auf Zeichenfolgen beschränkt ist, die tatsächlich in Ihrem Java-Code erscheinen können, aber nicht alle gewünschten Zeichenfolgen im Code ausgedrückt werden können. Beispielsweise benötigen Sie möglicherweise eine Zeichenfolge, die mit einer Zahl beginnt. name () kann diese Zeichenfolge niemals für Sie abrufen.

Intropie
quelle
-1

Sie können auch den folgenden Code verwenden. Ich habe Lombok verwendet, um zu vermeiden, dass einige der Boilerplate-Codes für Getter und Konstrukteure geschrieben werden.

@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
quelle