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?

Dori
fonte

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();

Buhake Sindi
fonte
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
vaichidrewar
fonte
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.

Bart Kiers
fonte
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.

Adrian Smith
fonte
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";      
}
hd42
fonte
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());
    }
}
Shohel Rana
fonte
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 .

Adam111p
fonte
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;
    }
}
Pravin
fonte