Java enum - зачем использовать toString вместо имени

Если вы посмотрите в enum api по методу name(), он говорит, что:

Возвращает имя этой константы перечисления, точно так же, как указано в объявлении перечисления.         Большинство программистов должны использовать метод toString, предпочитая это,         поскольку метод toString может возвращать более удобное имя.         Этот метод предназначен в первую очередь для использования в специализированных ситуациях, где правильность зависит от получения точного имени, которое не будет отличаться от выпуска к выпуску.

Почему лучше использовать toString()? Я хочу сказать, что toString может быть переопределено, когда name() уже является окончательным. Поэтому, если вы используете toString, а кто-то переопределяет его, чтобы вернуть твердое значение, все ваше приложение не работает... Также, если вы посмотрите в источниках, метод toString() возвращает точно и просто имя. Это то же самое.

Ответ 1

Это действительно зависит от того, что вы хотите сделать с возвращаемым значением:

  • Если вам нужно получить точное имя, используемое для объявления константы перечисления, вы должны использовать name(), поскольку toString может быть переопределен
  • Если вы хотите напечатать константу перечисления дружественным образом, вы должны использовать toString, который, возможно, был переопределен (или нет!).

Когда я чувствую, что это может запутать, я предоставляю более конкретный метод getXXX, например:

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

Ответ 2

Используйте name(), если вы хотите сделать сравнение или использовать жестко заданное значение для некоторого внутреннего использования в вашем коде.

Используйте toString(), когда вы хотите предоставить информацию пользователю (в том числе разработчику, просматривающему журнал). Никогда не полагайтесь на свой код на toString(), задавая определенное значение. Никогда не проверяйте его на определенную строку. Если ваш код ломается, когда кто-то правильно изменяет возврат toString(), то он уже был сломан.

Из javadoc (акцент мой):

Возвращает строковое представление объекта. В целом, Метод toString возвращает строку, в которой "текстовое обозначение" объект. Результат должен быть кратким, но информативным представлением это легко для человека для чтения. Рекомендуется, чтобы все подклассы переопределяют этот метод.

Ответ 3

name() является "встроенным" методом enum. Это окончательно, и вы не можете изменить его реализацию. Он возвращает имя константы перечисления, как она написана, например. в верхнем регистре, без пробелов и т.д.

Сравните MOBILE_PHONE_NUMBER и Mobile phone number. Какая версия более читаема? Я верю, второй. В этом разница: name() всегда возвращает MOBILE_PHONE_NUMBER, toString() может быть переопределен для возврата Mobile phone number.

Ответ 4

В то время как большинство людей слепо следуют советам javadoc, есть очень конкретные ситуации, когда вы хотите фактически избежать toString(). Например, я использую перечисления в своем Java-коде, но они должны быть сериализованы в базу данных и обратно. Если бы я использовал toString(), то я бы технически был подвержен переопределенному поведению, как указывали другие.

Кроме того, можно также дезацинировать из базы данных, например, это должно всегда работать в Java:

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

В то время как это не гарантируется:

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

Кстати, я считаю, что Javadoc явно говорит, что "большинство программистов должно". Я нахожу очень мало прецедентов в toString перечисления, если люди используют это для "дружественного имени", что явно плохой случай использования, поскольку они должны использовать что-то более совместимое с i18n, что в большинстве случаев, используйте метод name().

Ответ 5

name() - это буквально текстовое имя в java-коде перечисления. Это означает, что он ограничен строками, которые могут фактически отображаться в вашем java-коде, но не все желательные строки выражаются в коде. Например, вам может понадобиться строка, которая начинается с числа. name() никогда не сможет получить эту строку для вас.

Ответ 6

Практический пример, когда name() и toString() имеют смысл быть разными, - это шаблон, в котором для определения одноэлементного использования используется однозначное перечисление. Сначала это выглядит неожиданно, но имеет большой смысл:

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

    /* ...behavior... */

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

В таком случае:

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

Ответ 7

Вы также можете использовать что-то вроде кода ниже. Я использовал lombok, чтобы избежать написания шаблонных кодов для геттеров и конструкторов.

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