Лучший способ создать перечисление строк?

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

Кроме того, вы можете создать метод получения для text.

Теперь вы можете сделать Strings.STRING_ONE.toString();

Бухаке синди
источник
3
Я не знаю, является ли это требованием компилятора, но private String textдолжно быть окончательным.
Джонатан
7
@ Tomás Narros Да, вы все равно можете назначить его в конструкторе, если вы не зададите ему значение, когда объявляете его окончательным.
Джонатан
28
@ The Elite Gentleman Было бы плохо, если бы значение константы enum изменялось во время выполнения, поэтому, даже если оно не требуется, finalбыло бы лучше.
Джонатан
8
Не забывайте, что Enums не может быть сконструирован newкак конструктор private. По сути, создание объекта запрещено и finalне является действительно необходимым в этом случае.
Бухаке Синди
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 является его номинальное значение или имя элемента. Однако вы можете настроить строковое значение, переопределив метод 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
vaichidrewar
источник
16
Это не эффективный способ сделать это. Это создает новый пользовательский класс для каждого значения в перечислении. В приведенном выше примере вы увидите следующее в binкаталоге: EnumTest $ MyType.class EnumTest $ MyType $ 1.class EnumTest $ MyType $ 2.class, который будет очень быстро складываться . Лучше всего сделать это как ожидаемый ответ, передав значения в конструктор enum. Я на самом деле не согласен с переопределением toString(); Я считаю, что лучше использовать явный метод получения, такой как getKey()переопределение toString()может быть неожиданным для другого пользователя enum.
Мэтт Куигли
полностью согласен с @MattQuigley. Это поощряет пользователей использовать toString для вещей, для которых он не должен использоваться. Если вам нужен ярлык, вы бы предпочли добавить атрибут ярлыка
Себастьен Лорбер
Кроме того, нет никакого способа пойти другим путем (от строки до объекта enum), который, вероятно, потребуется в какой-то момент.
Адриан Смит
переопределение toString не влияет на valueOf (), не так ли?
Dmitriusan
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
@ Марк, правда, он не может обработать любой символ. Если операционному агенту нужен только один символ, это решение более прямолинейно, чем предложение The Elite Gentleman. Но на самом деле: если диапазон символов превышает тот, который может иметь действительный идентификатор Java, это не допускается. Хорошая точка зрения.
Барт Киерс
Весьма разумно иметь внутреннее соглашение об именах для перечисления, которое отличается от того, что вы хотели бы показать с помощью toString () (особенно, если пользователь видит вывод), поэтому я не думаю, что это было именно тем, что было в OP находясь в поиске.
Майкл МакГоуэн
17
Результат от name()может зависеть от программы обфускатора. Я столкнулся с подобной проблемой некоторое время назад. Например, с Proguard вам нужно обойти это. См. Перечисление Классов Перечисления
noisecapella
Это отлично. Работает со значениями, такими как: var_name, var_superlong_but_not_toooooo_long_name, даже и т.д. (без тройных точек)
19

Либо задайте имя 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.
}

Важно иметь константы вверху и методы / атрибуты внизу.

Адриан Смит
источник
А также иметь частного конструктора.
Бухаке Синди
1
Конструкторы enum по умолчанию являются закрытыми и не требуют модификатора доступа. Но это хороший момент для модификаторов доступа в целом, я обновил свой код, чтобы добавить их в атрибут и аксессор.
Эдриан Смит
15

В зависимости от того, что вы подразумеваете под «использовать их как строки», вы можете не использовать здесь enum. В большинстве случаев решение, предлагаемое The Elite Gentleman, позволит вам использовать их через их методы toString, например, в System.out.println(STRING_ONE)или String s = "Hello "+STRING_TWO, но когда вам действительно нужны строки (например STRING_ONE.toLowerCase()), вы можете предпочесть определить их как константы:

public interface Strings{
  public static final String STRING_ONE = "ONE";
  public static final String STRING_TWO = "TWO";      
}
hd42
источник
5
на самом деле это то, что я пытаюсь избежать ...!
Дори
На самом деле, если они также хотят, чтобы toLowerCase()мое решение, они могут пойти Strings.STRING_TWO.toString().toLowerCase().
Бухаке Синди
Конечно, но я не использую их как строки, как я их интерпретировал. Поскольку Рракхему, кажется, не требуется это использование, он, конечно, должен использовать предложенное решение enum.
hd42
6
Вы не должны использовать interfaceвместо finalкласса privateконструктор. Это обескураженная практика.
Алекс Н.
1
@mils, решения, использующие перечисления, работают так же хорошо в коммутаторе. Я бы предложил это решение, только если строки нужны напрямую.
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();
}

Я подозреваю, что это самое быстрое решение. Нет необходимости использовать переменные final .

Adam111p
источник
но с этим вам все равно придется вызывать getDescription (), из которого запрашивающий человек хочет вызвать ONE или получить доступ к нему как к константе.
Кинсли Каджива
Я предпочитаю это. Что будет, если потребуется принять больше информации? С этим решением просто добавьте защищенные абстрактные методы и переопределите его. Более того, нет необходимости переопределять метод 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;
    }
}
Pravin
источник