498

What is the best way to use the values stored in an Enum as String literals? For example:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3
}

Then later I could use Mode.mode1 to return its string representation as mode1. Without having to keep calling Mode.mode1.toString().

Marcello Grechi Lins
  • 3,350
  • 8
  • 38
  • 72
Larry
  • 11,439
  • 15
  • 61
  • 84

19 Answers19

788

You can't. I think you have FOUR options here. All four offer a solution but with a slightly different approach...

Option One: use the built-in name() on an enum. This is perfectly fine if you don't need any special naming format.

    String name = Modes.mode1.name(); // Returns the name of this enum constant, exactly as declared in its enum declaration.

Option Two: add overriding properties to your enums if you want more control

public enum Modes {
    mode1 ("Fancy Mode 1"),
    mode2 ("Fancy Mode 2"),
    mode3 ("Fancy Mode 3");

    private final String name;       

    private Modes(String s) {
        name = s;
    }

    public boolean equalsName(String otherName) {
        // (otherName == null) check is not needed because name.equals(null) returns false 
        return name.equals(otherName);
    }

    public String toString() {
       return this.name;
    }
}

Option Three: use static finals instead of enums:

public final class Modes {

    public static final String MODE_1 = "Fancy Mode 1";
    public static final String MODE_2 = "Fancy Mode 2";
    public static final String MODE_3 = "Fancy Mode 3";

    private Modes() { }
}

Option Four: interfaces have every field public, static and final:

public interface Modes {

    String MODE_1 = "Fancy Mode 1";
    String MODE_2 = "Fancy Mode 2";
    String MODE_3 = "Fancy Mode 3";  
}
Michael J. Lee
  • 12,278
  • 3
  • 23
  • 39
  • 61
    This answer is in fact wrong: as you can call `.name()` See: http://stackoverflow.com/a/6667365/887836 – Alexander Oh May 30 '16 at 13:49
  • 3
    @kato2 not correct. The .name() method is created automatically by the compiler – Sean Patrick Floyd Jan 06 '17 at 14:00
  • 16
    JavaDoc: **String java.lang.Enum.name()** Returns the name of this enum constant, exactly as declared in its enum declaration. **Most programmers should use the toString method in preference to this one, as the toString method may return a more user-friendly name.** This method is designed primarily for use in specialized situations where correctness depends on getting the exact name, which will not vary from release to release. Returns:the name of this enum constant – SuperRetro Apr 03 '17 at 09:28
  • 1
    The awser of @Ryan Stewart requires less code and less code == less chance of bugs – Eric Apr 13 '17 at 08:22
  • 9
    Don't use interfaces to hold constants: *Effective Java* (3rd edition) recommends to "use interfaces only to define types" (item 22). – Olivier Grégoire Jun 14 '18 at 11:27
  • Option 2 is not correct. For the working implementation of Option 2, check @vamsi answer below. – Mert Celik Mar 21 '19 at 09:50
  • @MertCelik Can you elaborate what is wrong with Option2 here? – GreenAsJade Apr 30 '19 at 02:23
  • How is using .name() any better than the .toString() that the OP was trying to avoid? – GreenAsJade Apr 30 '19 at 02:47
554

Every enum has both a name() and a valueOf(String) method. The former returns the string name of the enum, and the latter gives the enum value whose name is the string. Is this like what you're looking for?

String name = Modes.mode1.name();
Modes mode = Modes.valueOf(name);

There's also a static valueOf(Class, String) on Enum itself, so you could also use:

Modes mode = Enum.valueOf(Modes.class, name);
Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
  • 61
    THIS should be an ANSWER! Using something like A("A") can be source of errors and it is senseless extra work! – Firzen Apr 18 '14 at 09:42
  • 17
    @Firzen not if the string value is allowed to contain spaces or hyphens, which is the case in `some-really-long-string`. – ceving Jun 13 '14 at 15:28
  • @ceving The question is not phrased well in respect to spaces and hyphens. The questions shows a hyphenated example, but doesn't ask how to create an Enum using hyphenated values. Instead the question asks how to get the String value without having to call toString without specifying hyphenated values are a requirement. That said, I think this could be a better answer if it were amended to mention that the Enum values must still follow Java naming rules and would need to use something mentioned in the accepted answer if such characters were required. – Hazok May 15 '15 at 15:17
  • I wanted to add a link to [mkyong](http://www.mkyong.com/java/java-convert-string-to-enum-object/) who uses the `valueOf(String)` method in combination with `toUpperCase(Locale)` to ensure String conversion. – Unknown Id Oct 09 '15 at 07:45
  • 2
    The reason a lot of people prefer the property approach over Enum.name() is that logic based around Enum.name() is then forever at the mercy of the value names. If the code every changes in the future this could turn into a non trivial issue to get around as all the previous logic will break on changes to the Enum value set. Overriding and using the toString() approach allows the developer to have greater control over the values in use including duplication, non valid variable name characters etc. Just don't forget to also override valueOf(). – indivisible Apr 06 '17 at 15:21
  • Will the name change when using proguard? I want to use an enum name for logging, so it needs to stay the same. – Björn Kechel May 18 '17 at 15:04
102

You could override the toString() method for each enum value.

Example:

public enum Country {

  DE {
    @Override
    public String toString() {
      return "Germany";
    }
  },
  IT {
    @Override
    public String toString() {
      return "Italy";
    }
  },
  US {
    @Override
    public String toString() {
      return "United States";
    }
  }

}

Usage:

public static void main(String[] args) {
  System.out.println(Country.DE); // Germany
  System.out.println(Country.IT); // Italy
  System.out.println(Country.US); // United States
}
Benny Code
  • 51,456
  • 28
  • 233
  • 198
  • 3
    I like this. No reason not to use an enum as a class with further functionality such as get a list of all the values, get a string of each type, etc. – diegosasw Oct 01 '14 at 23:03
  • 14
    Ugly and not reusable. Much better to provide a string value as constructor for Country and then override the toString() method for the enum. – greg7gkb Mar 26 '15 at 22:36
  • @Larry should revisit this and tell if the original question required something else. Though other answers are very informative, I guess this is the only answer to the original question. – Mahesha999 Apr 10 '15 at 10:50
  • 6
    This is a good technique when you have quite a large enumeration and only want to override what things print as for one or two members. – Donal Fellows Sep 11 '15 at 11:38
  • 7
    This doesn't scale at all. Don't do this. – sebnukem Oct 23 '15 at 15:19
  • 1
    This works great for those smaller enums with under 5 values. – AntikM Jul 04 '21 at 16:45
47

As Benny Neugebauer mentions, you could overwrite the toString(). However instead overwriting the toString for each enum field I like more something like this:

public enum Country{
    SPAIN("España"),
    ITALY("Italia"),
    PORTUGAL("Portugal");


    private String value;

    Country(final String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    @Override
    public String toString() {
        return this.getValue();
    }
}

You could also add a static method to retrieve all the fields, to print them all, etc. Simply call getValue to obtain the string associated to each Enum item

diegosasw
  • 13,734
  • 16
  • 95
  • 159
34

mode1.name() or String.valueOf(mode1). It doesn't get better than that, I'm afraid

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
30
public enum Modes {
  MODE1("Mode1"),
  MODE2("Mode2"),
  MODE3("Mode3");

 private String value;
 public String getValue() {
    return value;
   }
 private Modes(String value) {
  this.value = value;
 } 
}

you can make a call like below wherever you want to get the value as a string from the enum.

Modes.MODE1.getvalue();

This will return "Mode1" as a String.

vamsi
  • 381
  • 5
  • 10
9

For my enums I don't really like to think of them being allocated with 1 String each. This is how I implement a toString() method on enums.

enum Animal
{
    DOG, CAT, BIRD;
    public String toString(){
        switch (this) {
            case DOG: return "Dog";
            case CAT: return "Cat";
            case BIRD: return "Bird";
        }
        return null;
    }
}
Ethan
  • 1,567
  • 11
  • 16
  • 1
    Throwing a runtime exception would be better instead of returning null since it should be unreachable code? – rents May 28 '18 at 09:37
  • 1
    The `return` is redundant, because switch on enums with all enums is terminating. – Danon May 17 '19 at 07:13
8

As far as I know, the only way to get the name would be

Mode.mode1.name();

If you really need it this way, however, you could do:

public enum Modes {
    mode1 ("Mode1"),
    mode2 ("Mode2"),
    mode3 ("Mode3");

    private String name;       

    private Modes(String s) {
        name = s;
    }
}
Jake Roussel
  • 631
  • 1
  • 6
  • 17
7

You can use Mode.mode1.name() however you often don't need to do this.

Mode mode =
System.out.println("The mode is "+mode);
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 7
    It's worth noting that the + operator will call toString() on the enum, and not name(). And toString() may be overridden to return something other than the name (even if it isn't desirable) – JB Nizet Jul 12 '11 at 16:05
  • 1
    Both `name()` and `toString()` can be overriden, but hopefully this will be clear from reading the code for the `enum` if this is happening. – Peter Lawrey Jul 12 '11 at 16:12
  • 9
    No. name() is final, and always returns the name of the enum as declared in its enum declaration. – JB Nizet Jul 12 '11 at 16:13
  • 1
    @JB Nizet, You are right. `name()` is `final`. Thank you for correcting me. :) – Peter Lawrey Jul 12 '11 at 16:20
6

my solution for your problem!

import java.util.HashMap;
import java.util.Map;

public enum MapEnumSample {
    Mustang("One of the fastest cars in the world!"), 
    Mercedes("One of the most beautiful cars in the world!"), 
    Ferrari("Ferrari or Mercedes, which one is the best?");

    private final String description;
    private static Map<String, String> enumMap;

    private MapEnumSample(String description) {
        this.description = description;
    }

    public String getEnumValue() {
        return description;
    }

    public static String getEnumKey(String name) {
        if (enumMap == null) {
            initializeMap();
        }
        return enumMap.get(name);
    }

    private static Map<String, String> initializeMap() {
        enumMap = new HashMap<String, String>();
        for (MapEnumSample access : MapEnumSample.values()) {
            enumMap.put(access.getEnumValue(), access.toString());
        }
        return enumMap;
    }

    public static void main(String[] args) {

        // getting value from Description
        System.out.println(MapEnumSample.getEnumKey("One of the fastest cars in the world!"));

        // getting value from Constant
        System.out.println(MapEnumSample.Mustang.getEnumValue());

        System.out.println(MapEnumSample.getEnumKey("One of the most beautiful cars in the world!"));
        System.out.println(MapEnumSample.Mercedes.getEnumValue());

        // doesnt exist in Enum
        System.out.println("Mustang or Mercedes, which one is the best?");
        System.out.println(MapEnumSample.getEnumKey("Mustang or Mercedes, which one is the best?") == null ? "I don't know!" : "I believe that "
                + MapEnumSample.getEnumKey("Ferrari or Mustang, which one is the best?") + " is the best!.");

        // exists in Enum
        System.out.println("Ferrari or Mercedes, wich one is the best?");
        System.out.println(MapEnumSample.getEnumKey("Ferrari or Mercedes, which one is the best?") == null ? "I don't know!" : "I believe that "
                + MapEnumSample.getEnumKey("Ferrari or Mercedes, which one is the best?") + " is the best!");

    }
}
niksvp
  • 5,545
  • 2
  • 24
  • 41
5

You can simply use:

""+ Modes.mode1
Buddy
  • 2,074
  • 1
  • 20
  • 30
  • I'm not 100% sure on this but as far as my knowledge goes this cast isn't necessary, is it? Concatenating an empty string with another variable should automatically call for a conversion, or are there any exceptions to this rule? – Unknown Id Oct 09 '15 at 07:39
  • 1
    You are right, the correct version should be `"" + Modes.mode1`. I fixed the answer – Buddy Oct 09 '15 at 11:13
  • E B's answer also benefits by being reminiscent of the python idiom `''.join()` – anthropic android Aug 23 '16 at 06:23
5
public enum Environment
{
    PROD("https://prod.domain.com:1088/"),
    SIT("https://sit.domain.com:2019/"),
    CIT("https://cit.domain.com:8080/"),
    DEV("https://dev.domain.com:21323/");

    private String url;

    Environment(String envUrl) {
        this.url = envUrl;
    }

    public String getUrl() {
        return url;
    }
}

String prodUrl = Environment.PROD.getUrl();

It will print:

https://prod.domain.com:1088/

This design for enum string constants works in most of the cases.

Lokesh Gupta
  • 463
  • 5
  • 8
4

Enum is just a little bit special class. Enums can store additional fields, implement methods etc. For example

public enum Modes {
    mode1('a'),
    mode2('b'),
    mode3('c'),
    ;
    char c;

    private Modes(char c) {
        this.c = c;
    }
    public char character() {
        return c;
    }
}

Now you can say:

System.out.println(Modes.mode1.character())

and see output: a

AlexR
  • 114,158
  • 16
  • 130
  • 208
3
package com.common.test;

public  enum Days {


    monday(1,"Monday"),tuesday(2,"Tuesday"),wednesday(3,"Wednesday"),
    thrusday(4,"Thrusday"),friday(5,"Friday"),saturday(6,"Saturday"),sunday(7,"Sunday");

    private int id;
    private String desc;


    Days(int id,String desc){
        this.id=id;
        this.desc=desc;
    }

    public static String getDay(int id){

        for (Days day : Days.values()) {
            if (day.getId() == id) {
                return day.getDesc();
            }
        }
        return null;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }



};
  • 1
    Can you pls explain on how it would resolve the issue ? – Phani Jan 28 '16 at 13:46
  • you can call this enum anywhere by using this line : int id=1; String dayName = Days.getDay(id); , pass here id . it will return Description for that id that is "Tuesday" –  Jan 29 '16 at 12:32
3

This method should work with any enum:

public enum MyEnum {
    VALUE1,
    VALUE2,
    VALUE3;

    public int getValue() {
        return this.ordinal();
    }

    public static DataType forValue(int value) {
        return values()[value];
    }

    public String toString() {
        return forValue(getValue()).name();
    }
}
Caner
  • 57,267
  • 35
  • 174
  • 180
1

i found this one is more easy for preventing type error:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3;

    String str;

    Modes(){
        this.str = super.name();
    }

    @Override
    @NonNull
    public String toString() {
        return str;
    }

however - this may work when you need to use a String on a log/println or whenever java compiles the toString() method automatically, but on a code line like this ->

// sample method that require (string,value)
intent.putExtra(Modes.mode1 ,shareElement.getMode()); // java error
// first argument enum does not return value

instead as mentioned above you will still have to extend the enum and use .name() in those cases like this:

intent.putExtra(Modes.mode1.name() ,shareElement.getMode()); 
ItzikH
  • 21
  • 5
0

after many tries I have come with this solution

public static enum Operation {

    Addition, Subtraction, Multiplication, Division,;

    public String getUserFriendlyString() {
        if (this==Addition) {
            return " + ";
        } else if (this==Subtraction) {
            return " - ";
        } else if (this==Multiplication) {
            return " * ";
        } else if (this==Division) {
            return " / ";
        }
        return "undefined";
       }
}
Basheer AL-MOMANI
  • 14,473
  • 9
  • 96
  • 92
0

You can try this:

public enum Modes {
    some-really-long-string,
    mode1,
    mode2,
    mode3;

    public String toString(){
        switch(this) {
            case some-really-long-string:
                return "some-really-long-string";
            case mode2:
                return "mode2";
            default: return "undefined";
        }
    }

}

Kamil Naja
  • 6,267
  • 6
  • 33
  • 47
0

use mode1.name() or String.valueOf(Modes.mode1)

Meryemb
  • 101
  • 3
  • 10