Java enum - por que usar toString em vez de nome

171

Se você olhar na enum api no método, name()ele diz que:

Retorna o nome dessa constante enum, exatamente como declarado em sua declaração enum. A maioria dos programadores deve usar o método toString em preferência a este, pois o método toString pode retornar um nome mais amigável. Esse método foi desenvolvido principalmente para uso em situações especializadas em que a correção depende da obtenção do nome exato, que não varia de versão para versão.

Por que é melhor usar toString()? Quero dizer, ToString pode ser substituído quando name () já é final. Portanto, se você usar toString e alguém o substituir para retornar um valor codificado, todo o aplicativo estará inativo ... Além disso, se você procurar nas fontes, o método toString () retornará exatamente e apenas o nome. É a mesma coisa.

spauny
fonte
4
Você pode substituir toString()sua enumeração, mas ninguém mais pode estendê-la e substituí-la. Você não pode estender enums.
Erick G. Hagstrom 22/03

Respostas:

199

Realmente depende do que você deseja fazer com o valor retornado:

  • Se você precisar obter o nome exato usado para declarar a constante enum, use-o name()como toStringpode ter sido substituído
  • Se você deseja imprimir a constante enum de uma maneira amigável, use o toStringque pode ter sido substituído (ou não!).

Quando sinto que pode ser confuso, forneço um getXXXmétodo mais específico , por exemplo:

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;
    }
}
assylias
fonte
1
Isso é aceitável. Embora se eles deixassem o enum ter uma classe base, as coisas seriam mais fáceis.
Ralphgabb 25/1018
55

Use name()quando quiser fazer uma comparação ou use o valor codificado para algum uso interno do seu código.

Use toString()quando quiser apresentar informações a um usuário (incluindo um desenvolvedor que esteja visualizando um log). Nunca confie no seu código para toString()fornecer um valor específico. Nunca teste contra uma sequência específica. Se o seu código quebrar quando alguém alterar corretamente o toString()retorno, ele já estará quebrado.

Do javadoc (ênfase minha):

Retorna uma representação de string do objeto. Em geral, o método toString retorna uma string que "representa textualmente" esse objeto. O resultado deve ser uma representação concisa, mas informativa, fácil para uma pessoa ler . É recomendável que todas as subclasses substituam esse método.

Denys Séguret
fonte
23

name()é um método "interno" de enum. É final e você não pode alterar sua implementação. Retorna o nome da constante enum como está escrito, por exemplo, em maiúsculas, sem espaços etc.

Compare MOBILE_PHONE_NUMBERe Mobile phone number. Qual versão é mais legível? Eu acredito no segundo. Esta é a diferença: name()sempre retorna MOBILE_PHONE_NUMBER, toString()pode ser cancelado para retornar Mobile phone number.

AlexR
fonte
16
Isso não está correto!! toString () retornará Mobile phone numberapenas se você substituí-lo para retornar esse valor. Caso contrário, ele irá retornarMOBILE_PHONE_NUMBER
spauny
2
@ spayny, é óbvio que você precisa substituir toString(). O problema é que name()não pode ser substituído, pois é final.
AlexR #
13
@AlexR, pode ser necessário incorporar o comentário acima na resposta para torná-lo 100% correto
artfullyContrived
5
Concordo com @artfullyContrived, pois não era óbvio para mim até ler seus comentários.
Martinatime 5/05
13

Enquanto a maioria das pessoas segue cegamente os conselhos do javadoc, há situações muito específicas em que você deseja realmente evitar toString (). Por exemplo, estou usando enumerações no meu código Java, mas elas precisam ser serializadas em um banco de dados e vice-versa. Se eu usasse toString (), estaria tecnicamente sujeito a obter o comportamento substituído, como outros já apontaram.

Além disso, também é possível desserializar do banco de dados, por exemplo, isso sempre deve funcionar em Java:

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

Considerando que isso não é garantido:

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

A propósito, acho muito estranho para o Javadoc dizer explicitamente "a maioria dos programadores deveria". Eu acho muito pouco caso de uso no toString de uma enumeração, se as pessoas o usarem para um "nome amigável", esse é claramente um caso de uso ruim, pois deveriam estar usando algo mais compatível com o i18n, o que, na maioria dos casos, use o método name ().

codificação
fonte
2
Obrigado por responder. Já faz quase 5 anos desde que fiz essa pergunta e ainda não usei o método toString () para uma enumeração! 99% das vezes eu uso enumerações exatamente para o que você descreveu: serializando e desserializando nomes de enumerações para / do banco de dados.
211717 spauny
5

Um exemplo prático em que name () e toString () fazem sentido para ser diferente é um padrão em que enum com valor único é usado para definir um singleton. Parece surpreendente no começo, mas faz muito sentido:

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

    /* ...behavior... */

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

Nesse caso:

SingletonComponent myComponent = SingletonComponent.INSTANCE;
assertThat(myComponent.name()).isEqualTo("INSTANCE"); // blah
assertThat(myComponent.toString()).isEqualTo("SingletonComponent"); // better
Marcin
fonte
Sim, você está certo ... um bom exemplo é o enum dos predicados da goiaba
spuny
4

name () é literalmente o nome textual no código java da enumeração. Isso significa que está limitado a strings que podem realmente aparecer no seu código java, mas nem todas as strings desejáveis ​​são expressas no código. Por exemplo, você pode precisar de uma sequência que comece com um número. name () nunca poderá obter essa string para você.

Intropy
fonte
-1

Você também pode usar algo como o código abaixo. Eu usei o lombok para evitar escrever alguns dos códigos padrão para getters e construtores.

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