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


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

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

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 .


но с этим вам все равно придется вызывать 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;
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.