Найкращий спосіб створити перелік струн?


364

Який найкращий спосіб мати enumтип представлення набору рядків?

Я спробував це:

enum Strings{
   STRING_ONE("ONE"), STRING_TWO("TWO")
}

Як я можу потім їх використовувати Strings?

Відповіді:


605

Я не знаю, що ви хочете зробити, але саме так я переклав ваш приклад код ....

package test;

/**
 * @author The Elite Gentleman
 *
 */
public enum Strings {
    STRING_ONE("ONE"),
    STRING_TWO("TWO")
    ;

    private final String text;

    /**
     * @param text
     */
    Strings(final String text) {
        this.text = text;
    }

    /* (non-Javadoc)
     * @see java.lang.Enum#toString()
     */
    @Override
    public String toString() {
        return text;
    }
}

Крім того, ви можете створити метод getter для text.

Тепер ви можете це зробити Strings.STRING_ONE.toString();


3
Я не знаю, чи це вимога компілятора, але вона private String textповинна бути остаточною.
Джонатан

7
@ Tomás Narros Так, ви все одно можете призначити його в конструкторі, якщо ви не надасте йому значення, коли ви оголосите його остаточним.
Джонатан

28
@ Елітний джентльмен Було б погано, якби значення константи enum змінювалося під час виконання, тому навіть якщо це не потрібно, finalбуло б найкращим.
Джонатан

8
Не забувайте, що Enums не може бути побудований newтак, як конструктор private. По суті, створення об'єктів заборонено і finalв цьому випадку насправді не потрібно.
Buhake Sindi

6
@BuhakeSindi: це правда, але випадково хтось може схильний поставити setText(String)на перелік, і це може розв'язати пекло :) finalвид документів, на ваш намір, що це константа з підтримкою компілятора. Якби ви використовували Stringконстанти, ви не визнавали б це так public static String, правда?
TWiStErRob

104

Спеціальні значення рядків для Enum

з http://javahowto.blogspot.com/2006/10/custom-string-values-for-enum.html

Значенням рядка за замовчуванням для java enum є його номінал або ім'я елемента. Однак ви можете налаштувати значення рядка, замінивши метод toString (). Наприклад,

public enum MyType {
  ONE {
      public String toString() {
          return "this is one";
      }
  },

  TWO {
      public String toString() {
          return "this is two";
      }
  }
}

Запуск наступного тестового коду призведе до цього:

public class EnumTest {
  public static void main(String[] args) {
      System.out.println(MyType.ONE);
      System.out.println(MyType.TWO);
  }
}


this is one
this is two

16
Це не ефективний спосіб зробити це. Це створює новий спеціальний клас для кожного значення в перерахунку. У наведеному вище прикладі, ви побачите наступне в binкаталозі: EnumTest $ MyType.class EnumTest $ MyType $ 1.class EnumTest $ MyType $ 2.class який додасть до реального швидко. Найкраще це зробити як очікувана відповідь, передавши значення конструктору enum. Я насправді не погоджуюся з переважаючим toString(); Я вважаю, що краще використовувати явний getter, наприклад, getKey()оскільки переосмислення toString()може бути несподіваним іншим користувачем enum.
Метт Квіглі

повністю згоден з @MattQuigley. Це заохочує користувачів використовувати toString для речей, для яких він не повинен використовуватися. Якщо вам потрібна мітка, ви краще додайте атрибут мітки
Sebastien Lorber

Крім того, немає іншого способу пройти навпаки (від рядка до об'єкта enum), що, ймовірно, буде потрібно в якийсь момент.
Адріан Сміт

перевизначення toString не впливає на valueOf (), чи не так?
Дмитріусан

69

Використовуйте його name()метод:

public class Main {
    public static void main(String[] args) throws Exception {
        System.out.println(Strings.ONE.name());
    }
}

enum Strings {
    ONE, TWO, THREE
}

врожайність ONE.


17
Так, але Strings.STRING_ONE.name()виходить "STRING_ONE", а не "ONE". Це просто не є гарною відповіддю. Ви не можете мати жодного рядка, який би не був дійсним ідентифікатором Java тощо.
Марк Петерс

2
@ Марк, правда, він не може впоратися з будь-яким символом. Якщо ОП бажає отримати єдину схему, це рішення є більш прямим, ніж пропозиція Елітного Джентльмена. Але насправді: якщо діапазон символів перевищує той, який може мати дійсний ідентифікатор Java, це неможливість. Гарна думка.
Барт Кіерс

Дуже розумним є внутрішній договір іменування для enum, який відрізняється від того, що хотілося б показати з toString () (особливо, якщо користувач бачить вихід), тому я не думаю, що це не зовсім те, що було в ОП шукаю.
Майкл МакГоуан

17
На результат name()може вплинути програма обфускатора. Я зіткнувся з подібною проблемою деякий час тому. Наприклад, з Proguard вам потрібно обійти це питання. Див. Розділ Обробка класів перерахування
Розділи

Це чудово. Працює з такими значеннями, як: var_name, var_superlong_but_not_toooooo_long_name, навіть тощо (без потрійних крапок)

18

Або встановіть ім'я enum таким же, як потрібна рядок, або, загалом, ви можете асоціювати довільні атрибути зі своїми значеннями enum:

enum Strings {
   STRING_ONE("ONE"), STRING_TWO("TWO");
   private final String stringValue;
   Strings(final String s) { stringValue = s; }
   public String toString() { return stringValue; }
   // further methods, attributes, etc.
}

Важливо мати константи вгорі, а методи / атрибути - внизу.


А також мати приватного конструктора.
Buhake Sindi

1
Конструктори enum за замовчуванням приватні і не потребують модифікатора доступу. Але це хороший момент щодо модифікаторів доступу взагалі, я оновив свій код, щоб додати їх до атрибута та аксесуара.
Адріан Сміт

15

Залежно від того, що ви маєте на увазі під «використовувати їх як рядки», ви, можливо, не захочете використовувати тут перерахунок. У більшості випадків, рішення , запропоноване The Elite Gentleman дозволить використовувати їх через ToString-методи, наприклад , в System.out.println(STRING_ONE)або String s = "Hello "+STRING_TWO, але якщо вам дійсно потрібно Strings (наприклад STRING_ONE.toLowerCase()), ви можете віддати перевагу їх визначення як константи:

public interface Strings{
  public static final String STRING_ONE = "ONE";
  public static final String STRING_TWO = "TWO";      
}

5
насправді це те, чого я намагаюся уникати ...!
Дорі

Насправді, якщо вони також захочуть toLowerCase()мого рішення, вони можуть піти Strings.STRING_TWO.toString().toLowerCase().
Buhake Sindi

Звичайно, але це не використання їх як рядків, як я його інтерпретував. Оскільки, схоже, Реракем не потребує такого використання, він, звичайно, повинен використовувати запропоноване рішення перерахунку.
hd42

6
Ви не повинні використовувати interfaceзамість finalкласу з privateконструктором. Це відсторонена практика.
Алекс Н.

1
@mils, рішення, що використовують enums, так само добре працюють в комутаторі. Я б запропонував це рішення тільки в тому випадку, якщо рядки потрібні безпосередньо.
hd42

8

Ви можете використовувати це для рядка Enum

public enum EnumTest {
    NAME_ONE("Name 1"),
    NAME_TWO("Name 2");

    private final String name;

    /**
     * @param name
     */
    private EnumTest(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

І дзвоніть з основного методу

public class Test {
    public static void main (String args[]){
        System.out.println(EnumTest.NAME_ONE.getName());
        System.out.println(EnumTest.NAME_TWO.getName());
    }
}

5

Якщо ви не хочете використовувати конструктори і хочете мати спеціальну назву методу, спробуйте це:

public enum MyType {
  ONE {
      public String getDescription() {
          return "this is one";
      }
  },    
  TWO {
      public String getDescription() {
          return "this is two";
      }
  };

  public abstract String getDescription();
}

Я підозрюю, що це найшвидше рішення. Немає необхідності використовувати змінні остаточні .


але з цим вам все одно потрібно зателефонувати getDescription (), з якого запитуючий бажає зателефонувати в ONE або отримати доступ до нього як постійний.
kinsley kajiva

Я вважаю за краще це. Що буде, якщо йому потрібно приймати більше інформації? За допомогою цього рішення просто додайте захищені абстрактні методи та перекладіть їх. Більше не потрібно переосмислювати метод toString (). Його чисто і можна прийняти як найкращу відповідь.
Арундев

0

Отримайте та встановіть значення за замовчуванням.

public enum Status {

    STATUS_A("Status A"),  STATUS_B("Status B"),

    private String status;

    Status(String status) {
        this.status = status;
    }

    public String getStatus() {
        return status;
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.