使用Enum值作为String文字


389

使用存储在Enum中作为字符串文字的值的最佳方法是什么?例如:

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

然后,我可以用Mode.mode1它返回它的字符串表示形式mode1。不必继续打电话Mode.mode1.toString()

Answers:


646

你不能 我认为您在这里有四个选择。四个都提供了解决方案,但方法略有不同。

选项一: name()枚举中使用内置函数。如果您不需要任何特殊的命名格式,那就很好了。

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

方法二: 如果需要更多控制,请向您的枚举中添加重写属性

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

选项三: 使用静态的final代替枚举:

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() { }
}

选项四: 接口具有每个字段的公共字段,静态字段和最终字段:

public interface Modes {

    String MODE_1 = "Fancy Mode 1";
    String MODE_2 = "Fancy Mode 2";
    String MODE_3 = "Fancy Mode 3";  
}

46
这个答案实际上是错误的:您可以致电.name()查看:stackoverflow.com/a/6667365/887836
Alex

3
@ kato2不正确。由编译器自动创建的。名称()方法
肖恩帕特里克弗洛伊德

10
JavaDoc: 字符串java.lang.Enum.name() 返回此枚举常量的名称,与它的枚举声明中声明的完全相同。大多数程序员应该优先使用toString方法,因为toString方法可能返回更用户友好的名称。此方法主要设计用于在特殊情况下正确性取决于获得确切名称的特殊情况,具体名称在发行版本之间不会有所不同。返回:此枚举常量的名称
SuperRetro

@Ryan Stewart的awser需要更少的代码,更少的代码==更少的错误机会
Eric

4
不要使用接口来保存常量:有效的Java(第3版)建议“仅使用接口定义类型”(项目22)。
奥利维尔·格雷戈尔(OlivierGrégoire),

481

每个枚举都具有name()和valueOf(String)方法。前者返回枚举的字符串名称,后者给出名称为字符串的枚举值。这是您想要的吗?

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

Enum本身也有一个静态valueOf(Class,String),因此您也可以使用

Modes mode = Enum.valueOf(Modes.class, name);

50
这应该是一个答案!使用类似A(“ A”)的东西可能会导致错误,这是多余的工作!
Firzen 2014年

12
如果字符串值允许包含空格或连字符,则@Firzen不能,在中就是这种情况some-really-long-string
ceving

@ceving对于空格和连字符,问题措辞不佳。这些问题显示了一个带连字符的示例,但没有询问如何使用带连字符的值创建一个Enum。取而代之的是,该问题询问如何获得String值,而无需调用toString而不指定连字符值是必需的。就是说,我认为如果将其修改为提及Enum值必须仍然遵循Java命名规则,并且如果需要这样的字符,则需要使用接受的答案中提到的内容,那么这可能是一个更好的答案。
哈佐2015年

我想向mkyong添加一个链接,该链接valueOf(String)结合使用该方法toUpperCase(Locale)以确保String转换。
未知ID

2
与Enum.name()相比,很多人更喜欢使用属性方法的原因是,基于Enum.name()的逻辑永远永远受值名称的支配。如果代码将来会发生每一次更改,那么可能会变成一个不小的问题,因为以前的所有逻辑都会因对Enum值集的更改而中断。重写和使用toString()方法使开发人员可以更好地控制使用中的值,包括重复项,无效的变量名字符等。请不要忘记也重写valueOf()。
不可分割

79

您可以覆盖toString()每个枚举值的方法。

例:

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

}

用法:

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
}

2
我喜欢这个。没有理由不使用枚举作为具有更多功能的类,例如获取所有值的列表,获取每种类型的字符串等
。– diegosasw 2014年

8
丑陋且不可重用。为Country提供一个字符串值作为构造函数,然后为枚举覆盖toString()方法,会更好。
greg7gkb

4
当您有大量的枚举并且只想覆盖一个或两个成员的打印内容时,这是一种很好的技术。
Donal Fellows 2015年

3
这根本无法扩展。不要这样
sebnukem

1
这对我来说很有意义
hanzolo 2016年

35

正如Benny Neugebauer所提到的,您可以覆盖toString()。但是,代替覆盖每个枚举字段的toString,我更喜欢这样的事情:

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

您还可以添加一个静态方法来检索所有字段,打印所有字段等。只需调用getValue即可获取与每个Enum项关联的字符串。



21
public enum Modes {
  MODE1("Mode1"),
  MODE2("Mode2"),
  MODE3("Mode3");

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

您可以在任何要从枚举中获取字符串形式的值的地方进行如下调用。

Modes.MODE1.getvalue();

这将返回“ Mode1”作为字符串。


6

您可以使用,Mode.mode1.name()但是您通常不需要这样做。

Mode mode =
System.out.println("The mode is "+mode);

6
值得注意的是,+运算符将在枚举上调用toString(),而不是name()。并且toString()可能会被覆盖以返回名称以外的其他内容(即使不希望这样做)
JB Nizet

1
双方name()toString()可以被覆盖,但希望这将通过阅读代码的明确enum,如果发生这种情况。
彼得·劳瑞

9
否。name()是最终的,并且始终返回其枚举声明中声明的枚举的名称。
JB Nizet

1
@JB Nizet,你是​​对的。name()final。谢谢你纠正我。:)
Peter Lawrey 2011年

6

据我所知,唯一获得名称的方法是

Mode.mode1.name();

但是,如果您确实需要这种方式,则可以执行以下操作:

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

    private String name;       

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

1
但是在这种情况下,Mode.mode1仍然不是type String
拉里

啊对。您需要一个getName()方法,该方法无法达到目的,所以不,您不能这样做。
杰克·罗素

“名称”是错误的字段名称,它是枚举的标准字段。
Wooff

6

对于我的枚举,我不是很想将它们分配给每个字符串。这就是我对枚举实现toString()方法的方式。

enum Animal
{
    DOG, CAT, BIRD;
    public String toString(){
        switch (this) {
            case DOG: return "Dog";
            case CAT: return "Cat";
            case BIRD: return "Bird";
        }
        return null;
    }
}

1
抛出运行时异常比返回null更好,因为它应该是无法访问的代码?
出租

return是多余的,因为打开具有所有枚举的枚举将终止。

5

您可以简单地使用:

""+ Modes.mode1

我对此不是100%的确定,但就我所知,此演员不是必需的,对吗?将空字符串与另一个变量连接应该自动调用转换,或者该规则是否有例外?
未知ID

1
您是正确的,正确的版本应该是"" + Modes.mode1。我确定了答案
好友2015年

EB的答案还受益于让人想起python惯用语 ''.join()
人类的android系统

5

我为您解决的问题!

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!");

    }
}

看来OP的问题已在4年前解决,但欢迎使用StackOverflow :)
TDG 2015年

1
谢谢,只是为了帮助像我这样的人,寻找针对老问题的更客观答案:)
Renan Galdino da Silva 2015年

3

枚举只是一些特殊的类。枚举可以存储其他字段,实现方法等。例如

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

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

现在您可以说:

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

并查看输出: a


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
您能否解释如何解决该问题?
Phani

您可以使用此行在任何地方调用此枚举:int id = 1; 字符串dayName = Days.getDay(id); ,在此处传递id。它将返回描述该ID是“星期二”

2

此方法适用于任何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();
    }
}

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

它将打印:

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

枚举字符串常量的这种设计在大多数情况下都有效。


0

经过多次尝试,我提出了这种解决方案

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

0

您可以尝试以下方法:

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

}


0

我发现这更容易防止类型错误:

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

    String str;

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

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

但是-这可能在您需要在log / println上使用String或每当java自动编译toString()方法但在这样的代码行上使用->时有效

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

相反,如上所述,您仍然必须扩展枚举并.name() 在如下情况下使用:

intent.putExtra(Modes.mode1.name() ,shareElement.getMode()); 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.