Melhor maneira de criar enum de strings?


364

Qual é a melhor maneira de fazer com que um enumtipo represente um conjunto de strings?

Eu tentei isso:

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

Como posso então usá-los como Strings?

Respostas:


605

Não sei o que você quer fazer, mas foi assim que traduzi seu código de exemplo ....

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

Como alternativa, você pode criar um método getter para text .

Agora você pode fazer Strings.STRING_ONE.toString();


3
Não sei se é um requisito do compilador, mas private String textdeve ser final.
— Jonathan

7
@ Tomás Narros Sim, você ainda pode atribuir a ele no construtor, desde que não atribua um valor ao declará-lo final.
— Jonathan

28
@ The Elite Gentleman Seria ruim se o valor de uma constante enum fosse alterado durante o tempo de execução, portanto, mesmo que não seja necessário, finalseria melhor.
— Jonathan

8
Não esqueça que Enums não podem ser construídos com newo construtor private. Essencialmente, a criação de objetos é proibida e finalnão é realmente necessária neste caso.
— Buhake Sindi

6
@BuhakeSindi: isso é verdade, mas acidentalmente alguém pode estar interessado setText(String)em enum e isso pode desencadear o inferno :) finalmeio que documenta sua intenção de que é uma constante com o suporte ao compilador. Se você usasse Stringconstantes, não o declararia public static String, certo?
— 213144 TWIStErRob

104

Valores de sequência personalizados para enum

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

O valor padrão da string para java enum é seu valor de face ou o nome do elemento. No entanto, você pode personalizar o valor da sequência substituindo o método toString (). Por exemplo,

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

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

A execução do seguinte código de teste produzirá isso:

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
Esta não é uma maneira eficiente de fazer isso. Isso cria uma nova classe personalizada para cada valor na enumeração. No exemplo acima, você verá o seguinte no bindiretório: EnumTest $ MyType.class EnumTest $ MyType $ 1.class EnumTest $ MyType $ 2.class que somará reais rápido. É melhor fazê-lo como a resposta esperada, passando valores ao construtor enum. Na verdade, eu discordo de substituir toString(); Eu acredito que é melhor usar um getter explícito, como a getKey()substituição toString()pode ser inesperada por outro usuário da enum.
— Matt Quigley

concordo totalmente com @MattQuigley. Isso incentiva os usuários a usar toString para coisas que não devem ser usadas. Se você precisar de um rótulo, adicione um atributo de rótulo
— Sebastien Lorber

Além disso, não há como ir ao contrário (de uma string para o objeto enum) que provavelmente será necessário em algum momento.
— Adrian Smith

substituir toString não afeta valueOf (), afeta?
— Dmitriusan

69

Use seu name()método:

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

enum Strings {
    ONE, TWO, THREE
}

rendimentos ONE.


17
Sim, mas Strings.STRING_ONE.name()gera "STRING_ONE", não "ONE". Isso simplesmente não é uma boa resposta. Você não pode ter nenhuma String que não seja um identificador Java válido etc.
— Mark Peters

2
@ Mark, é verdade, ele não pode lidar com nenhum personagem. Se o OP quer apenas um único caractere, essa solução é mais direta do que a sugestão The Elite Gentleman. Mas, de fato: se o intervalo de caracteres exceder os que um identificador Java válido pode ter, isso é um impedimento. Bom ponto.
— Bart Kiers 20/10/10

É muito razoável ter uma convenção de nomenclatura interna para uma enumeração diferente do que alguém gostaria de mostrar com toString () (especialmente se um usuário vê a saída), então eu não acho que isso seja exatamente o que o OP era procurando por.
— Michael McGowan

17
O resultado name()pode ser afetado por um programa ofuscador. Encontrei um problema semelhante há um tempo atrás. Por exemplo, com o Proguard, você precisa solucionar isso. Consulte Processando classes de enumeração
— noisecapella

Isto e excelente. Funciona com valores como: var_name, var_superlong_but_not_toooooo_long_name, mesmo etc (sem os pontos tripple)

18

Defina o nome da enumeração para ser o mesmo que a sequência desejada ou, de maneira mais geral, você pode associar atributos arbitrários aos seus valores de enumeração:

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

É importante ter as constantes no topo e os métodos / atributos na parte inferior.


E também para ter um construtor privado .
— Buhake Sindi

11
Os construtores enum são privados por padrão e não precisam de modificador de acesso. Mas esse é um bom argumento sobre modificadores de acesso em geral. Atualizei meu código para adicioná-los ao atributo e acessador.
— Adrian Smith

15

Dependendo do que você quer dizer com "use-as como Strings", talvez você não queira usar uma enumeração aqui. Na maioria dos casos, a solução proposta pelo The Elite Gentleman permitirá que você os use por meio dos métodos toString, por exemplo, em System.out.println(STRING_ONE)ou String s = "Hello "+STRING_TWO, mas quando você realmente precisar de Strings (por exemplo STRING_ONE.toLowerCase()), poderá preferir defini-los como constantes:

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

5
na verdade é isso que estou tentando evitar ...!
— Dori

Na verdade, se eles também querem a toLowerCase()minha solução, eles podem ir Strings.STRING_TWO.toString().toLowerCase().
— Buhake Sindi

Claro, mas isso não é usá-los como strings como eu o interpretei. Como Rrackham não parece exigir esse uso, ele deve usar a solução de enumeração proposta.
— hd42

6
Você não deve usar interfaceno lugar de uma finalclasse com o privateconstrutor. É uma prática desencorajada.
— 22414 Aleks N.

11
@mils, as soluções que usam enums funcionam tão bem em um switch. Eu sugeriria esta solução somente se Strings forem necessárias diretamente.
— hd42

8

Você pode usar isso para a string 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;
    }
}

E chamar do método principal

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

5

Se você não deseja usar construtores e deseja ter um nome especial para o método, tente o seguinte:

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

  public abstract String getDescription();
}

Suspeito que esta seja a solução mais rápida . Não há necessidade de usar variáveis ​​finais .


mas com esse, você ainda precisa chamar getDescription (), do qual a pessoa que deseja ligar chama ONE e acessá-lo como uma constante.
— kajiva kinsley

Eu prefiro isso. O que acontecerá se precisar aceitar mais informações? Com esta solução, adicione métodos abstratos protegidos e substitua-os. Além disso, não é necessário substituir o método toString (). É limpo e pode ser aceito como a melhor resposta.
— Arundev #

0

Obtenha e defina com valores padrão.

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;
    }
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.