Il modo migliore per creare enum di stringhe?


364

Qual è il modo migliore per fare in modo che un enumtipo rappresenti un insieme di stringhe?

Ho provato questo:

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

Come posso quindi usarli come Strings?

Risposte:


605

Non so cosa vuoi fare, ma è così che ho tradotto il tuo codice di esempio ...

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

In alternativa, puoi creare un metodo getter per text .

Ora puoi farlo Strings.STRING_ONE.toString();


3
Non so se si tratta di un requisito del compilatore, ma private String textdovrebbe essere definitivo.
Jonathan,

7
@ Tomás Narros Sì, puoi ancora assegnarglielo nel costruttore, purché non gli dai un valore quando lo dichiari definitivo.
Jonathan,

28
@The Elite Gentleman Sarebbe negativo se il valore di una costante enum cambiasse durante il runtime, quindi anche se non richiesto, finalsarebbe il migliore.
Jonathan,

8
Non dimenticare che Enum non può essere costruito newcome lo è il costruttore private. In sostanza, la creazione di oggetti è vietata e finalnon è realmente necessaria in questo caso.
Buhake Sindi,

6
@BuhakeSindi: è vero, ma per caso si potrebbe essere inclini a mettere un setText(String)enum e questo può scatenare l'inferno :) finaltipo di documenti il ​​tuo intento che è una costante con il supporto del compilatore. Se dovessi usare le Stringcostanti non lo dichiareresti public static String, giusto?
TWiStErRob,

104

Valori stringa personalizzati per Enum

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

Il valore di stringa predefinito per java enum è il suo valore nominale o il nome dell'elemento. Tuttavia, è possibile personalizzare il valore della stringa sovrascrivendo il metodo toString (). Per esempio,

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

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

L'esecuzione del seguente codice di test produrrà questo:

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
Questo non è un modo efficace per farlo. Ciò crea una nuova classe personalizzata per ogni valore nell'enumerazione. Nell'esempio di cui sopra, si vedrà quanto segue nel bindirectory: EnumTest $ MyType.class EnumTest $ MyType $ 1.class EnumTest $ MyType $ 2.class, che si sommano reale veloce. Meglio farlo come la risposta prevista, passando valori al costruttore enum. In realtà non sono d'accordo con l'override toString(); Credo che sia meglio usare un getter esplicito come getKey()poiché l'override toString()può essere inaspettato da un altro utente dell'enum.
Matt Quigley,

sono totalmente d'accordo con @MattQuigley. In questo modo incoraggiare gli utenti ad usare toString per cose per cui non dovrebbero essere usate. Se hai bisogno di un'etichetta, preferiresti aggiungere un attributo etichetta
Sebastien Lorber,

Inoltre, non c'è modo di fare il contrario (da una stringa all'oggetto enum) che probabilmente sarà richiesto ad un certo punto.
Adrian Smith,

sovrascrivere toString non influisce su valueOf (), vero?
Dmitriusan,

69

Usa il suo name()metodo:

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

enum Strings {
    ONE, TWO, THREE
}

rese ONE.


17
Sì, ma Strings.STRING_ONE.name()produce "STRING_ONE", non "ONE". Questa semplicemente non è una buona risposta. Non puoi avere una stringa che non sia un identificatore Java valido, ecc.
Mark Peters,

2
@Mark, vero, non può gestire nessun personaggio. Se l'OP vuole solo un singolo carattere, questa soluzione è più semplice rispetto al suggerimento di The Elite Gentleman. Ma in effetti: se l'intervallo di caratteri supera quelli che un identificatore Java valido può avere, questo è un no-go. Buon punto.
Bart Kiers,

È molto ragionevole avere una convenzione di denominazione interna per un enum che è diverso da quello che si vorrebbe mostrare con toString () (specialmente se un utente vede l'output), quindi non penso che questo sia esattamente ciò che l'OP era cercando.
Michael McGowan,

17
Il risultato name()può essere influenzato da un programma di offuscamento. Mi sono imbattuto in un problema simile qualche tempo fa. Ad esempio, con Proguard è necessario aggirare il problema. Vedere Elaborazione delle classi di enumerazione
noisecapella,

Questo è eccellente Funziona con valori come: var_name, var_superlong_but_not_toooooo_long_name, anche ecc. (Senza i punti

19

Impostare il nome enum in modo che corrisponda alla stringa desiderata o, più in generale, è possibile associare attributi arbitrari ai valori 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.
}

È importante avere le costanti in alto e i metodi / attributi in basso.


E anche avere un costruttore privato .
Buhake Sindi,

1
I costruttori enum sono privati ​​per impostazione predefinita e non richiedono alcun modificatore di accesso. Ma questo è un buon punto sui modificatori di accesso in generale, ho aggiornato il mio codice per aggiungerli all'attributo e all'accessor.
Adrian Smith,

15

A seconda di cosa intendi per "usali come stringhe", potresti non voler usare un enum qui. Nella maggior parte dei casi, la soluzione proposta da The Elite Gentleman ti permetterà di usarli attraverso i loro metodi toString, ad esempio in System.out.println(STRING_ONE)o String s = "Hello "+STRING_TWO, ma quando hai davvero bisogno di stringhe (ad esempio STRING_ONE.toLowerCase()), potresti preferire definirli come costanti:

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

5
in realtà questo è quello che sto cercando di evitare ...!
Dori,

In realtà, se vogliono anche la toLowerCase()mia soluzione, possono andare Strings.STRING_TWO.toString().toLowerCase().
Buhake Sindi,

Certo, ma non li sto usando come stringhe come l'ho interpretato. Dato che Rrackham non sembra richiedere quell'uso, ovviamente dovrebbe usare la soluzione enum proposta.
hd42,

6
Non dovresti usare interfaceal posto di una finalclasse con privatecostruttore. È una pratica scoraggiata.
Aleks N.

1
@mils, le soluzioni che usano enum funzionano altrettanto bene in uno switch. Suggerirei questa soluzione solo se le stringhe sono necessarie direttamente.
hd42

8

Puoi usarlo per la stringa 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 chiama dal metodo principale

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 non si desidera utilizzare i costruttori e si desidera avere un nome speciale per il metodo, provare questo:

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

  public abstract String getDescription();
}

Sospetto che questa sia la soluzione più rapida . Non è necessario utilizzare le variabili final .


ma con questo devi ancora chiamare getDescription () di cui la persona che chiede vuole chiamare UNO o accedervi come costante.
Kinsley Kajiva,

Preferisco questo. Cosa succederà se è necessario accettare ulteriori informazioni? Con questa soluzione basta aggiungere metodi astratti protetti e sostituirlo. Inoltre non è necessario eseguire l'override del metodo toString (). È pulito e può essere accettato come la migliore risposta.
Arundev,

0

Ottieni e imposta con i valori predefiniti.

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;
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.