Enum Java: perché usare toString invece di name


171

Se guardi nell'enum api il metodo name(), dice che:

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.

Perché è meglio usare toString()? Voglio dire che String può essere ignorato quando name () è già definitivo. Quindi, se usi toString e qualcuno lo sovrascrive per restituire un valore hardcoded, l'intera applicazione è inattiva ... Inoltre, se cerchi nelle fonti il ​​metodo toString () restituisce esattamente e solo il nome. È la stessa cosa.


4
Puoi scavalcare il toString()tuo enum, ma nessun altro può estenderlo e scavalcarlo. Non puoi estendere enumerazioni.
Erick G. Hagstrom,

Risposte:


199

Dipende davvero da cosa vuoi fare con il valore restituito:

  • Se è necessario ottenere il nome esatto utilizzato per dichiarare la costante enum, è necessario utilizzare name()come toStringpotrebbe essere stato sostituito
  • Se si desidera stampare la costante enum in modo intuitivo, è necessario utilizzare toStringquale potrebbe essere stato sostituito (o no!).

Quando ritengo che possa essere fonte di confusione, fornisco un getXXXmetodo più specifico , ad esempio:

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

1
Questo è accettabile Sebbene se lasciano che enum abbia una classe base le cose sarebbero più facili.
ralphgabb,

55

Utilizzare name()quando si desidera effettuare un confronto o utilizzare il valore codificato per un uso interno nel codice.

Utilizzare toString()quando si desidera presentare informazioni a un utente (incluso uno sviluppatore che guarda un registro). Non affidarti mai al tuo codice per toString()dare un valore specifico. Non testarlo mai su una stringa specifica. Se il tuo codice si interrompe quando qualcuno modifica correttamente il toString()reso, è stato già interrotto.

Dal javadoc (l'enfasi mia):

Restituisce una rappresentazione in formato stringa dell'oggetto. In generale, il metodo toString restituisce una stringa che "rappresenta testualmente" questo oggetto. Il risultato dovrebbe essere una rappresentazione concisa ma informativa che è facile da leggere per una persona . Si consiglia a tutte le sottoclassi di ignorare questo metodo.


23

name()è un metodo "incorporato" di enum. È definitivo e non è possibile modificarne l'implementazione. Restituisce il nome della costante enum così come è scritta, ad esempio in maiuscolo, senza spazi ecc.

Confronta MOBILE_PHONE_NUMBERe Mobile phone number. Quale versione è più leggibile? Credo il secondo. Questa è la differenza: name()ritorna sempre MOBILE_PHONE_NUMBER, toString()può essere annullato per tornare Mobile phone number.


16
Questo non è corretto !! toString () restituisce Mobile phone numbersolo se lo si sovrascrive per restituire tale valore. Altrimenti torneràMOBILE_PHONE_NUMBER
spauny l'

2
@spayny, è ovvio che devi scavalcare toString(). Il name()problema è che non può essere ignorato poiché è definitivo.
AlexR

13
@AlexR potresti aver bisogno di incorporare il tuo commento sopra nella risposta per renderlo corretto al 100%
abilmente controllato

5
Sono d'accordo con @artfullyContrived in quanto non era ovvio per me fino a quando ho letto i tuoi commenti.
martinatime

13

Mentre la maggior parte delle persone segue ciecamente i consigli di javadoc, ci sono situazioni molto specifiche in cui si desidera effettivamente evitare toString (). Ad esempio, sto usando enum nel mio codice Java, ma devono essere serializzati in un database e viceversa. Se avessi usato ToString (), sarei tecnicamente soggetto a ottenere il comportamento ignorato, come altri hanno sottolineato.

Inoltre si può anche deserializzare dal database, ad esempio, questo dovrebbe sempre funzionare in Java:

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

Considerando che questo non è garantito:

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

A proposito, trovo molto strano per Javadoc dire esplicitamente "la maggior parte dei programmatori dovrebbe". Trovo pochissimo caso d'uso nel toString di un enum, se le persone lo usano per un "nome descrittivo" che è chiaramente un caso d'uso povero in quanto dovrebbero usare qualcosa di più compatibile con i18n, che, nella maggior parte dei casi, usa il metodo name ().


2
Grazie per aver risposto. Sono passati quasi 5 anni da quando ho fatto questa domanda e devo ancora usare il metodo toString () per un enum! Il 99% delle volte che uso enum esattamente per quello che hai descritto: serializzare e deserializzare i nomi enum da / verso il database.
spauny

5

Un esempio pratico in cui name () e toString () hanno senso essere diversi è uno schema in cui viene usato enum a valore singolo per definire un singleton. All'inizio sembra sorprendentemente ma ha molto senso:

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

    /* ...behavior... */

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

In tal caso:

SingletonComponent myComponent = SingletonComponent.INSTANCE;
assertThat(myComponent.name()).isEqualTo("INSTANCE"); // blah
assertThat(myComponent.toString()).isEqualTo("SingletonComponent"); // better

Sì, hai ragione ... un buon esempio è l'enum Predicates di Guava
spauny

4

name () è letteralmente il nome testuale nel codice java dell'enum. Ciò significa che è limitato alle stringhe che possono effettivamente apparire nel codice java, ma non tutte le stringhe desiderabili sono espresse nel codice. Ad esempio, potresti aver bisogno di una stringa che inizia con un numero. name () non sarà mai in grado di ottenere quella stringa per te.


-1

Puoi anche usare qualcosa come il codice qui sotto. Ho usato lombok per evitare di scrivere alcuni dei codici del boilerplate per getter e costruttore.

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