Java enum - навіщо використовувати toString замість імені


171

Якщо ви подивитесь на enum api на метод, name()він говорить, що:

Повертає ім'я цієї константи перерахунку, точно так, як заявлено в її декларації перерахунку. Більшість програмістів повинні використовувати метод toString віддати перевагу цьому, оскільки метод toString може повернути більш зручне ім'я. Цей метод розроблений насамперед для використання в спеціалізованих ситуаціях, коли від правильності залежить отримання точного імені, яке не буде змінюватися від випуску до випуску.

Чому краще використовувати toString()? Я маю на увазі, що toString може бути відмінено, коли name () вже остаточне. Тож якщо ви використовуєте toString і хтось замінює його, щоб повернути важко кодоване значення, вся ваша програма знижена ... Крім того, якщо ви подивитесь на джерела, метод toString () повертає саме та саме ім'я. Це те саме.


4
Ви можете перекрити toString()свою перерахунок, але ніхто більше не може її розширити і перекрити. Ви не можете продовжувати перерахунки.
Ерік Г. Хагстром

Відповіді:


198

Це дійсно залежить від того, що ви хочете зробити з поверненим значенням:

  • Якщо вам потрібно отримати точне ім’я, яке використовується для оголошення постійної перерахунку, вам слід скористатись 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;
    }
}

1
Це прийнятно. Хоча якби вони дозволили перелічити мати базовий клас, все було б простіше.
ralphgabb

55

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

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

Від javadoc (акцент міна):

Повертає рядкове подання об'єкта. Взагалі метод toString повертає рядок, який "текстуально представляє" цей об'єкт. Результатом має бути стисле, але інформативне подання, яке людині легко читати . Рекомендується, щоб цей підклас перекрив цей метод.


23

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

Порівняйте MOBILE_PHONE_NUMBERі Mobile phone number. Яка версія є більш читаною? Я вірю другому. У цьому різниця: name()завжди повертається MOBILE_PHONE_NUMBER, toString()може бути відмінено для повернення Mobile phone number.


16
Це неправильно !! toString () повертається Mobile phone numberлише в тому випадку, якщо ви його замініть, щоб повернути таке значення. Інакше повернетьсяMOBILE_PHONE_NUMBER
спауні

2
@spayny, очевидно, що вам доведеться перекрити toString(). Улов полягає в тому, що name()його неможливо змінити, оскільки він остаточний.
AlexR

13
@AlexR вам може знадобитися включити ваш вище коментар у відповідь, щоб зробити його на 100% правильним
майстерноЗавантажено

5
Я погоджуюся з @artfullyContrived, оскільки мені це було очевидно, поки я не прочитав ваші коментарі.
мартінаті

13

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

Крім того, можна також десериалізувати базу даних, наприклад, це завжди має працювати на Java:

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

Тоді як це не гарантується:

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

До речі, мені здається, що Javadoc чітко каже «більшість програмістів має». Я знаходжу дуже мало корисного випадку в toString enum, якщо люди використовують це для "доброзичливого імені", це явно поганий випадок використання, оскільки вони повинні використовувати щось більш сумісне з i18n, що, в більшості випадків, використовувати метод name ().


2
Дякую за відповідь. Минуло майже 5 років, як я поставив це запитання, і я все ще використовую метод toString () для перерахунку! У 99% випадків я використовую enums саме для того, що ви описали: серіалізація та десеріалізація імен enum до / з бази даних.
spauny

5

Практичний приклад, коли ім'я () та 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

Так, ти маєш рацію ... хороший приклад
припущення про перерахунок Гуави

4

name () - це буквально текстове ім'я в коді java enum. Це означає, що він обмежений рядками, які насправді можуть відображатися у вашому коді Java, але не всі бажані рядки можуть бути виразними в коді. Наприклад, вам може знадобитися рядок, що починається з числа. name () ніколи не зможе отримати цей рядок для вас.


-1

Ви також можете використовувати щось на зразок коду, наведеного нижче. Я використовував 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;
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.