【问题标题】:Using Enum values as String literals使用枚举值作为字符串文字
【发布时间】:2011-10-03 18:42:27
【问题描述】:

将存储在枚举中的值用作字符串文字的最佳方法是什么? 例如:

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

然后我可以使用Mode.mode1 将其字符串表示形式返回为mode1。无需继续拨打Mode.mode1.toString()

【问题讨论】:

    标签: java string enums


    【解决方案1】:

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

    选项一: 在枚举上使用内置的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;
        }
    }
    

    选项三: 使用静态终结符代替枚举:

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

    【讨论】:

    • 这个答案实际上是错误的:你可以打电话给.name() 见:stackoverflow.com/a/6667365/887836
    • @kato2 不正确。 .name() 方法由编译器自动创建
    • JavaDoc: String java.lang.Enum.name() 返回此枚举常量的名称,与其枚举声明中的声明完全相同。 大多数程序员应该优先使用 toString 方法,因为 toString 方法可能会返回一个对用户更友好的名称。 此方法主要设计用于正确性取决于获取确切信息的特殊情况名称,不会因版本而异。返回:此枚举常量的名称
    • @Ryan Stewart 的 awser 需要更少的代码和更少的代码 == 更少的错误机会
    • 不要使用接口来保存常量:Effective Java(第 3 版)建议“仅使用接口来定义类型”(第 22 条)。
    【解决方案2】:

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

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

    Enum 本身还有一个静态的valueOf(Class, String),所以你也可以使用:

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

    【讨论】:

    • 这应该是一个答案!使用 A("A") 之类的东西可能会导致错误,而且这是毫无意义的额外工作!
    • @Firzen 如果允许字符串值包含空格或连字符,则不会,some-really-long-string 就是这种情况。
    • @ceving 这个问题在空格和连字符方面的措辞不好。这些问题显示了一个带连字符的示例,但没有询问如何使用带连字符的值创建枚举。相反,问题询问如何在不指定连字符值的情况下调用 toString 来获取 String 值是必需的。也就是说,我认为这可能是一个更好的答案,如果它被修改为提到 Enum 值仍然必须遵循 Java 命名规则,并且如果需要这些字符,则需要使用已接受的答案中提到的内容。
    • 我想添加一个指向mkyong 的链接,他使用valueOf(String) 方法与toUpperCase(Locale) 结合来确保字符串转换。
    • 很多人比 Enum.name() 更喜欢属性方法的原因是基于 Enum.name() 的逻辑永远受值名称的支配。如果将来代码每次都发生变化,这可能会变成一个非常重要的问题,因为所有先前的逻辑都会在 Enum 值集的更改时中断。覆盖和使用 toString() 方法允许开发人员更好地控制正在使用的值,包括重复、无效的变量名字符等。只是不要忘记也覆盖 valueOf()。
    【解决方案3】:

    您可以为每个枚举值覆盖 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
    }
    

    【讨论】:

    • 我喜欢这个。没有理由不将枚举用作具有更多功能的类,例如获取所有值的列表、获取每种类型的字符串等。
    • 丑陋且不可重复使用。最好提供一个字符串值作为 Country 的构造函数,然后覆盖枚举的 toString() 方法。
    • 当您有相当大的枚举并且只想覆盖一两个成员的打印内容时,这是一种很好的技术。
    • 这根本无法扩展。不要这样做。
    • 这对于那些小于 5 个值的较小枚举非常有用。
    【解决方案4】:

    正如 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 项关联的字符串

    【讨论】:

      【解决方案5】:

      mode1.name()String.valueOf(mode1)。恐怕没有比这更好的了

      【讨论】:

        【解决方案6】:
        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”作为字符串。

        【讨论】:

          【解决方案7】:

          对于我的枚举,我真的不喜欢认为它们每个都分配有 1 个字符串。这就是我在枚举上实现 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;
              }
          }
          

          【讨论】:

          • 抛出运行时异常比返回 null 更好,因为它应该是无法访问的代码?
          • return 是多余的,因为打开所有枚举的枚举正在终止。
          【解决方案8】:

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

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

          【讨论】:

          • 值得注意的是,+ 运算符将在枚举上调用 toString(),而不是 name()。并且 toString() 可能会被覆盖以返回名称以外的其他内容(即使它是不可取的)
          • name()toString() 都可以被覆盖,但如果发生这种情况,希望通过阅读 enum 的代码可以清楚这一点。
          • 没有。 name() 是最终的,并且总是返回枚举声明中声明的枚举名称。
          • @JB Nizet,你是​​对的。 name()final。谢谢你纠正我。 :)
          【解决方案9】:

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

          Mode.mode1.name();
          

          如果你真的需要这种方式,你可以这样做:

          public enum Modes {
              mode1 ("Mode1"),
              mode2 ("Mode2"),
              mode3 ("Mode3");
          
              private String name;       
          
              private Modes(String s) {
                  name = s;
              }
          }
          

          【讨论】:

          • 但在这种情况下,Mode.mode1 仍然不是String 类型。
          • 哦,对了。你需要一个 getName() 方法,这种方法违背了目的,所以不,你不能这样做。
          • "name" 是错误的字段名称,它是枚举的标准字段。
          【解决方案10】:

          你可以简单地使用:

          ""+ Modes.mode1
          

          【讨论】:

          • 我对此不是 100% 确定,但据我所知,这个演员表没有必要,是吗?将空字符串与另一个变量连接应该会自动调用转换,或者此规则是否有任何例外?
          • 你是对的,正确的版本应该是"" + Modes.mode1。我确定了答案
          • EB 的回答也让人想起 python 成语''.join()
          【解决方案11】:

          我的解决方案!

          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 :)
          • 谢谢,只是为了帮助像我这样的人,为老问题寻找更客观的答案:)
          【解决方案12】:

          Enum 只是一个特殊的类。枚举可以存储额外的字段,实现方法等。例如

          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

          【讨论】:

            【解决方案13】:
            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;
                }
            
            
            
            };
            

            【讨论】:

            • 您能解释一下如何解决这个问题吗?
            • 您可以使用此行在任何地方调用此枚举:int id=1; String dayName = Days.getDay(id); ,在这里传递 id 。它将返回“星期二”的 id 的描述
            【解决方案14】:
            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/
            

            enum string constants 的这种设计适用于大多数情况。

            【讨论】:

            • 哦。这就像 Rust 和 Haskell。
            • 为什么这会将 PROD 退回给我?
            【解决方案15】:

            这个方法应该适用于任何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();
                }
            }
            

            【讨论】:

              【解决方案16】:

              经过多次尝试,我得到了这个解决方案

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

              【讨论】:

                【解决方案17】:

                你可以试试这个:

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

                }

                【讨论】:

                  【解决方案18】:

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

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

                  【讨论】:

                    【解决方案19】:

                    使用mode1.name()String.valueOf(Modes.mode1)

                    【讨论】:

                    • 请在您的答案中添加一些解释,以便其他人可以从中学习
                    猜你喜欢
                    • 2011-03-27
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-01-15
                    • 1970-01-01
                    • 2022-01-17
                    • 2023-03-04
                    • 1970-01-01
                    相关资源
                    最近更新 更多