Java enum: por que usar toString en lugar de name

171

Si miras en la API de enumeración el método name()dice que:

Devuelve el nombre de esta constante enum, exactamente como se declara en su declaración enum. La mayoría de los programadores deben usar el método toString con preferencia a este, ya que el método toString puede devolver un nombre más fácil de usar. Este método está diseñado principalmente para su uso en situaciones especializadas donde la corrección depende de obtener el nombre exacto, que no variará de una versión a otra.

¿Por qué es mejor usar toString()? Quiero decir que toString puede anularse cuando name () ya es final. Entonces, si usa toString y alguien lo anula para devolver un valor codificado, toda su aplicación está inactiva ... Además, si mira en las fuentes, el método toString () devuelve exactamente y solo el nombre. Es lo mismo.

spauny
fuente
44
Puede anular toString()en su enumeración, pero nadie más puede extenderla y anularla. No puedes extender las enumeraciones.
Erick G. Hagstrom

Respuestas:

199

Realmente depende de lo que quieras hacer con el valor devuelto:

  • Si necesita obtener el nombre exacto utilizado para declarar la enumeración constante, debe usarlo name()como toStringpuede haberse anulado
  • Si desea imprimir la enumeración constante de una manera fácil de usar, debe usar la toStringque puede haber sido anulada (¡o no!).

Cuando siento que puede ser confuso, proporciono un getXXXmétodo más específico , por ejemplo:

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;
    }
}
asilias
fuente
1
Esto es aceptable Aunque si permitieran que enum tuviera una clase base, las cosas serían más fáciles.
ralphgabb
55

Úselo name()cuando desee hacer una comparación o use el valor codificado para algún uso interno en su código.

Úselo toString()cuando desee presentar información a un usuario (incluido un desarrollador que mira un registro). Nunca confíe en su código para toString()dar un valor específico. Nunca lo pruebe contra una cadena específica. Si su código se rompe cuando alguien cambia correctamente la toString()devolución, entonces ya estaba roto.

Del javadoc (énfasis mío):

Devuelve una representación de cadena del objeto. En general, el método toString devuelve una cadena que "representa textualmente" este objeto. El resultado debe ser una representación concisa pero informativa que sea fácil de leer para una persona . Se recomienda que todas las subclases anulen este método.

Denys Séguret
fuente
23

name()es un método "incorporado" de enum. Es definitivo y no puede cambiar su implementación. Devuelve el nombre de enum constante tal como está escrito, por ejemplo, en mayúsculas, sin espacios, etc.

Compara MOBILE_PHONE_NUMBERy Mobile phone number. ¿Qué versión es más legible? Yo creo el segundo. Esta es la diferencia: name()siempre regresa MOBILE_PHONE_NUMBER, toString()puede ser anulado para regresar Mobile phone number.

AlexR
fuente
16
¡¡Esto no es correcto!! toString () Mobile phone numbersolo se devuelve si lo anula para devolver dicho valor. De lo contrario, volveráMOBILE_PHONE_NUMBER
spauny
2
@spayny, es obvio que tienes que anular toString(). El problema es que name()no se puede anular ya que es final.
AlexR
13
@AlexR puede que necesite incorporar su comentario anterior en la respuesta para que sea 100% correcto
artfullyContrived
55
Estoy de acuerdo con @artfullyContrived ya que no era obvio para mí hasta que leí tus comentarios.
Martinatime 05 de
13

Si bien la mayoría de las personas siguen ciegamente los consejos del javadoc, hay situaciones muy específicas en las que desea evitar toString (). Por ejemplo, estoy usando enumeraciones en mi código Java, pero necesitan ser serializadas en una base de datos y volver a aparecer. Si solía toString (), técnicamente estaría sujeto a obtener el comportamiento anulado como otros han señalado.

Además, también se puede deserializar de la base de datos, por ejemplo, esto siempre debería funcionar en Java:

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

Mientras que esto no está garantizado:

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

Por cierto, me parece muy extraño que el Javadoc diga explícitamente "la mayoría de los programadores deberían". Encuentro muy poco caso de uso en toString de una enumeración, si las personas lo usan para un "nombre descriptivo" que es claramente un caso de uso deficiente, ya que deberían estar usando algo más compatible con i18n, que, en la mayoría de los casos, usa el método name ().

codificación
fuente
2
Gracias por responder. ¡Han pasado casi 5 años desde que hice esta pregunta y todavía tengo que usar el método toString () para una enumeración! El 99% de las veces utilizo enumeraciones exactamente para lo que usted describió: serializar y deserializar nombres de enumeración hacia / desde la base de datos.
Spauny
5

Un ejemplo práctico cuando name () y toString () tienen sentido para ser diferentes es un patrón donde se usa una enumeración de un solo valor para definir un singleton. Parece sorprendente al principio, pero tiene mucho sentido:

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

    /* ...behavior... */

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

En tal caso:

SingletonComponent myComponent = SingletonComponent.INSTANCE;
assertThat(myComponent.name()).isEqualTo("INSTANCE"); // blah
assertThat(myComponent.toString()).isEqualTo("SingletonComponent"); // better
Marcin
fuente
Sí, tienes razón ... un buen ejemplo son los predicados de enumeración de guayaba
spauny
4

name () es literalmente el nombre textual en el código java de la enumeración. Eso significa que está limitado a cadenas que realmente pueden aparecer en su código Java, pero no todas las cadenas deseables se pueden expresar en el código. Por ejemplo, puede necesitar una cadena que comience con un número. name () nunca podrá obtener esa cadena por usted.

Intropía
fuente
-1

También puede usar algo como el código a continuación. Usé lombok para evitar escribir algunos de los códigos repetitivos para captadores y constructores.

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