422

What is the best way to have a enum type represent a set of strings?

I tried this:

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

How can I then use them as Strings?

Dori
  • 18,283
  • 17
  • 74
  • 116

8 Answers8

700

I don't know what you want to do, but this is how I actually translated your example code....

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

Alternatively, you can create a getter method for text.

You can now do Strings.STRING_ONE.toString();

Zon
  • 18,610
  • 7
  • 91
  • 99
Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
  • 5
    I don't know if it is a compiler requirement, but `private String text` should be final. – Jonathan Oct 20 '10 at 15:25
  • @Jonathan, if it were final, I think that you could not assing a value at the constructor. Could you? – Tomas Narros Oct 20 '10 at 15:36
  • 7
    @Tomás Narros Yes, you can still assign to it in the constructor, as long as you don't give it a value when you declare it final. – Jonathan Oct 20 '10 at 15:39
  • 39
    @The Elite Gentleman It would be bad if the value of an enum constant changed during runtime, so even if not required, `final` would be best. – Jonathan Oct 20 '10 at 15:40
  • @Jonathan: Thanks. This is something I've never used (always intialized final fields at declaration). – Tomas Narros Oct 20 '10 at 16:15
  • 9
    Don't forget that Enums cannot be constructed with `new` as the constructor is `private`. Essentially, object creation is prohibited and `final` is not really necessary in this case. – Buhake Sindi Apr 15 '13 at 14:46
  • 7
    @BuhakeSindi: that's true, but accidentally one may be inclined to put a `setText(String)` on the enum and that can unleash hell :) `final` kind of documents your intent that it's a constant with compiler support. If you were to use `String` constants you wouldn't declare it as `public static String`, right? – TWiStErRob Jun 13 '14 at 21:15
  • @buhake-sindi Also, my IDE indicates that private is redundant for enum constructors. – comiventor Dec 26 '17 at 07:40
  • 2
    @comiventor that's true. An `enum` constructor is `private` by default. – Buhake Sindi Dec 27 '17 at 18:22
  • As are all `enum`s `public` by default. – Alex Apr 29 '21 at 12:24
119

Custom String Values for Enum

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

The default string value for java enum is its face value, or the element name. However, you can customize the string value by overriding toString() method. For example,

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

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

Running the following test code will produce this:

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
  • 9,251
  • 18
  • 72
  • 86
  • 22
    This is *not* an efficient way to do this. This creates a new custom class for every value in the enumeration. In the above example, you'll see the following in the `bin` directory: EnumTest$MyType.class EnumTest$MyType$1.class EnumTest$MyType$2.class which will add up _real_ quick. Best to do it as the expected answer, by passing in values to the enum constructor. I actually disagree with overriding `toString()`; I believe it's better to use an explicit getter such as `getKey()` since overriding `toString()` may be unexpected by another user of the enum. – Matt Quigley Aug 18 '14 at 17:31
  • totally agree with @MattQuigley . Doing so encourage users to use toString for things it should not be used for. If you need a label, you'd rather add a label attribute – Sebastien Lorber Nov 01 '14 at 21:54
  • Also, there is no way to go the other way around (from a string to the enum object) which is probably going to be required at some point. – Adrian Smith Nov 03 '14 at 10:49
  • This may not be efficient, but it certainly is a language capability that most programmers do not know about. – Richard Jessop Feb 10 '21 at 17:16
77

Use its name() method:

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

enum Strings {
    ONE, TWO, THREE
}

yields ONE.

Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
  • 23
    Yeah, but `Strings.STRING_ONE.name()` yields "STRING_ONE", not "ONE". This simply isn't a good answer. You can't have any String that wouldn't be a valid Java identifier, etc. – Mark Peters Oct 20 '10 at 14:29
  • 2
    @Mark, true, it can't handle any character. If the OP just wants a single char, this solution is more straight forward than The Elite Gentleman suggestion. But indeed: if the range of characters exceeds the ones a valid Java identifier can have, this is a no-go. Good point. – Bart Kiers Oct 20 '10 at 14:37
  • It is very reasonable to have an internal naming convention for an enum that is different from what one would want to show with toString() (especially if a user sees the output), so I don't think this is quite what the OP was looking for. – Michael McGowan Oct 20 '10 at 14:59
  • 21
    The result from `name()` may be affected by a obfuscator program. I ran into a similar problem a while ago. For instance, with Proguard you need to work around this. See [Processing Enumeration Classes](http://proguard.sourceforge.net/manual/examples.html#enumerations) – noisecapella Sep 21 '12 at 21:01
22

Either set the enum name to be the same as the string you want or, more generally,you can associate arbitrary attributes with your enum values:

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

It's important to have the constants at the top, and the methods/attributes at the bottom.

pixel
  • 24,905
  • 36
  • 149
  • 251
Adrian Smith
  • 17,236
  • 11
  • 71
  • 93
  • And also to have a **private** constructor. – Buhake Sindi Oct 20 '10 at 14:05
  • 2
    enum constructors are private by default and require no access modifier. But that's a good point about access modifiers in general, I have updated my code to add them to the attribute and accessor. – Adrian Smith Oct 20 '10 at 14:19
19

Depending on what you mean by "use them as Strings", you might not want to use an enum here. In most cases, the solution proposed by The Elite Gentleman will allow you to use them through their toString-methods, e.g. in System.out.println(STRING_ONE) or String s = "Hello "+STRING_TWO, but when you really need Strings (e.g. STRING_ONE.toLowerCase()), you might prefer defining them as constants:

public interface Strings{
  public static final String STRING_ONE = "ONE";
  public static final String STRING_TWO = "TWO";      
}
hd42
  • 1,741
  • 15
  • 30
  • 7
    actually this is what i am trying to avoid...! – Dori Oct 21 '10 at 09:20
  • Actually, if they also want the `toLowerCase()` on my solution, they can go `Strings.STRING_TWO.toString().toLowerCase()`. – Buhake Sindi Oct 21 '10 at 12:54
  • Sure, but that is not using them as strings as I interpreted it. As Rrackham doesn't seem to require that use, he of course should use the proposed enum solution. – hd42 Oct 27 '10 at 09:18
  • 10
    You shouldn't use `interface` in place of a `final` class with `private` constructor. It's a discouraged practice. – Aleks N. Aug 22 '14 at 12:39
  • This is great because you can use it _inside_ a class, and inner _classes_ can *not* have static members. – bnieland Nov 16 '16 at 15:49
  • This will also work inside a `switch()` statement, where the other solutions will not – mils Feb 17 '18 at 11:37
  • 1
    @mils, the solutions using enums work just as well in a switch. I would suggest this solution only if Strings are needed directly. – hd42 Feb 19 '18 at 07:05
  • Enum's are the best way to create constants. Initially we feel its difficult but once you started to do that, you will always use enums. Even using a reflection we can't change value inside an enums. – Arundev Apr 05 '19 at 09:50
  • Is it really required? public static final – Dheeraj D May 13 '19 at 15:48
  • @DheerajD, no, it is not. They could be (package)private or protected dependeing on their use. But this is realy only for the edge case where you absolutely need Strings and not enum values. – hd42 May 14 '19 at 06:27
14

You can use that for 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;
    }
}

And call from main method

public class Test {
    public static void main (String args[]){
        System.out.println(EnumTest.NAME_ONE.getName());
        System.out.println(EnumTest.NAME_TWO.getName());
    }
}
mvermand
  • 5,829
  • 7
  • 48
  • 74
Shohel Rana
  • 2,332
  • 19
  • 24
8

If you do not want to use constructors, and you want to have a special name for the method, try it this:

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

  public abstract String getDescription();
}

I suspect that this is the quickest solution. There is no need to use variables final.

Adam111p
  • 3,469
  • 1
  • 23
  • 18
  • 1
    but with this one you still have to call getDescription() of which the asking person wants to call ONE or access it as a constant. – kinsley kajiva Sep 13 '17 at 06:19
  • 1
    I prefer this. What will happen if it need to accept more informations? With this solution just add protected abstract methods and overide it. More over no need to override toString() method. Its clean and can be accept as best answer. – Arundev Apr 05 '19 at 09:55
2

Get and set with default values.

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;
  }
}
Abraham
  • 8,525
  • 5
  • 47
  • 53
Pravin Bansal
  • 4,315
  • 1
  • 28
  • 19