在Java枚举中重写valueof()和toString()

在Java枚举中重写valueof()和toString(),java,enums,overriding,tostring,value-of,Java,Enums,Overriding,Tostring,Value Of,myenum中的值是需要在其中包含空格的单词,但是enum的值中不能包含空格,因此所有的值都聚集在一起。我想重写toString(),在我告诉它的地方添加这些空格 我还希望当我在添加空格的同一字符串上使用valueOf()时,枚举提供正确的枚举 例如: public enum RandomEnum { StartHere, StopHere } 在值为StartHere的RandomEnum上调用toString(),返回字符串“从这里开始”。对同一字符串调用valueof

my
enum
中的值是需要在其中包含空格的单词,但是enum的值中不能包含空格,因此所有的值都聚集在一起。我想重写
toString()
,在我告诉它的地方添加这些空格

我还希望当我在添加空格的同一字符串上使用
valueOf()
时,枚举提供正确的枚举

例如:

public enum RandomEnum
{
     StartHere,
     StopHere
}
在值为
StartHere
RandomEnum
上调用
toString()
,返回字符串
“从这里开始”
。对同一字符串调用
valueof()
“从这里开始”
)返回枚举值
从那里开始


我怎样才能做到这一点呢?

我认为你不会让valueOf(“从这里开始”)发挥作用。 但就空间而言…请尝试以下方法

static private enum RandomEnum {
    R("Start There"), 
    G("Start Here"); 
    String value;
    RandomEnum(String s) {
        value = s;
    }
}

System.out.println(RandomEnum.G.value);
System.out.println(RandomEnum.valueOf("G").value);

Start Here
Start Here

你可以试试这个代码。由于无法重写
valueOf
方法,因此必须定义一个自定义方法(
getEnum
,在下面的示例代码中),该方法返回所需的值,并将客户端更改为使用此方法

public enum RandomEnum {

    StartHere("Start Here"),
    StopHere("Stop Here");

    private String value;

    RandomEnum(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

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

    public static RandomEnum getEnum(String value) {
        for(RandomEnum v : values())
            if(v.getValue().equalsIgnoreCase(value)) return v;
        throw new IllegalArgumentException();
    }
}

下面是valueOf()的一个很好的通用替代方案


可以在枚举中使用静态映射,将字符串映射到枚举常量。在“getEnum”静态方法中使用它。这样,每当您希望从枚举的字符串值中获取枚举时,就不需要遍历枚举

public enum RandomEnum {

    StartHere("Start Here"),
    StopHere("Stop Here");

    private final String strVal;
    private RandomEnum(String strVal) {
        this.strVal = strVal;
    }

    public static RandomEnum getEnum(String strVal) {
        if(!strValMap.containsKey(strVal)) {
            throw new IllegalArgumentException("Unknown String Value: " + strVal);
        }
        return strValMap.get(strVal);
    }

    private static final Map<String, RandomEnum> strValMap;
    static {
        final Map<String, RandomEnum> tmpMap = Maps.newHashMap();
        for(final RandomEnum en : RandomEnum.values()) {
            tmpMap.put(en.strVal, en);
        }
        strValMap = ImmutableMap.copyOf(tmpMap);
    }

    @Override
    public String toString() {
        return strVal;
    }
}
公共枚举随机枚举{
StartHere(“从这里开始”),
停在这里(“停在这里”);
私有最终字符串strVal;
私有随机枚举(字符串strVal){
this.strVal=strVal;
}
公共静态随机枚举getEnum(字符串strVal){
如果(!strValMap.containsKey(strVal)){
抛出新的IllegalArgumentException(“未知字符串值:”+strVal);
}
返回strValMap.get(strVal);
}
私有静态最终映射strValMap;
静止的{
最终映射tmpMap=Maps.newHashMap();
对于(最终随机数en:RandomEnum.values()){
tmpMap.put(en.strVal,en);
}
strValMap=ImmutableMap.copyOf(tmpMap);
}
@凌驾
公共字符串toString(){
返回strVal;
}
}
只需确保映射的静态初始化发生在枚举常量声明的下面

顺便说一句,“ImmutableMap”类型来自GoogleGuavaAPI,在这种情况下我绝对推荐它


编辑-根据评论:

  • 此解决方案假定每个分配的字符串值都是唯一的且非空。鉴于枚举的创建者可以控制这一点,并且字符串对应于唯一的非空枚举值,这似乎是一个安全的限制
  • 我添加了问题中要求的“toSTring()”方法

  • 试试这个,但我不确定在任何地方都能用:)


    Java8实现怎么样?(空值可由默认枚举替换)

    或者您可以使用:

    ...findAny().orElseThrow(NotFoundException::new);
    

    您仍然可以在枚举中实现以下选项:

    public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name){...}
    
    publicstatict-valueOf(类枚举类型,字符串名称){…}
    

    添加“Java”标记以获取更多注释/答案。可能的重复是使用
    compareTo()
    equals()
    更优雅地处理字符串?优雅不是问题-我同意
    .equals()
    可以正常工作。如果您愿意,可以使用
    ==
    。(尽管不这样做的理由很好,但您应该用类替换枚举。)@exception永远不要使用==进行字符串比较,因为它将执行对象相等性检查,而您需要的是内容相等性检查,并使用String类的equals()方法。如果您执行以下操作,则可能会缩短getEnum在Java 6+中不适用的时间:v.getValue().等于(价值);可以省略空检查。您也可以懒洋洋地构建映射并重用它,但在构建映射时要注意线程问题。在无法将valueOf()方法的调用更改为getValue()的情况下,这种方法不起作用,例如,当您通过Hibernate注释定义某些字段以映射到枚举值时,直到Java中的枚举被修复,@Bat有一个更合适、更友好的解决方案。name()不应是final.for,而可以使用valueOf(randomnum.class,value);我在这个答案上收到了几张反对票——有人想进一步说明为什么这个答案不好吗?我只是好奇人们是怎么想的。如果场景中有多个enum常量具有相同的“值”,比如
    RestartHere(“replay”)、ReplayHere(“replay”)
    ,或者根本没有“值”,比如
    PauseHere、WaitHere
    (即enum有一个默认构造函数,类似于
    private randomnum(){This.strVal=null;}
    您应该使用ImmutableMap.Builder,而不是创建一个MutableMap来构建+ImmutableMap::copyOf。这看起来很有趣,但是如果枚举只有几个不同的值,那么迭代它们不会花费太长时间。可能只有当枚举有很多值时才值得。为什么我是唯一一个看到这种东西的人邪恶?我的意思是它看起来很酷,但是没有上下文的人读代码很可能像“WTF?”。@NicolasGuillaume这类代码,如果实现,将迫切需要一个注释来解释它为什么存在以及程序员试图解决什么问题。:-)不要捕捉一般异常,因为这可能是出于记忆或其他原因,这是一个可怕的想法。其中最重要的一点是可能出现无指示或无恢复的无声错误。现在代码中的“名称”值和符号值(例如A、B)也不同了+因为聪明-200英镑,因为他非常聪明。我不可能批准这项代码审查。@pedorro这似乎并不像你说的那么糟糕。任何理解Java委员会所做的一切不应被视为福音的人都会在代码审查中通过这一点。更糟糕的是,必须重写并维护所有的枚举实用程序方法,因为name()不能被重写。因斯蒂亚
    public static RandomEnum getEnum(String value) {
        return Arrays.stream(RandomEnum.values()).filter(m -> m.value.equals(value)).findAny().orElse(null);
    }
    
    ...findAny().orElseThrow(NotFoundException::new);
    
    public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name){...}