枚举';s toString方法和Java良好实践

枚举';s toString方法和Java良好实践,java,jsf,enums,Java,Jsf,Enums,我想问一下Java中良好的编码实践。我想创建一些属性的枚举,并重写toString()以以下方式使用它(JSF 1.2用于检索本地化消息): 我的问题是关于良好实践。将所有这些方法放在enum定义中是否被认为是好的?如果没有,我想了解为什么以及如何做得更好。这里有两点需要说明: 如果默认情况(代码中返回null)是运行时错误,那么使用开关有点容易出错。我认为有两个更好的选择: 使用在枚举实例的构造函数中初始化的字段localizationKey,并在toString方法中引用此键 或者,(对于更

我想问一下Java中良好的编码实践。我想创建一些属性的枚举,并重写
toString()
以以下方式使用它(
JSF 1.2
用于检索本地化消息):


我的问题是关于良好实践。将所有这些方法放在
enum
定义中是否被认为是好的?如果没有,我想了解为什么以及如何做得更好。

这里有两点需要说明:

  • 如果默认情况(代码中返回null)是运行时错误,那么使用
    开关
    有点容易出错。我认为有两个更好的选择:

  • 使用在枚举实例的构造函数中初始化的字段
    localizationKey
    ,并在
    toString
    方法中引用此键
  • 或者,(对于更复杂的情况)将
    toString
    抽象化,并强制使用正确的实现覆盖每个实例。例如,见
  • 许多人认为,
    toString
    要么用于真正明显的实现,要么仅用于调试。我的建议是:使用更具描述性的方法名,不要为了方便而重用
    toString


  • 更新:稍微缩小Java语义:正如BalusC在下面的评论中指出的那样,此逻辑属于视图而不是模型。

    我将确保所有复杂逻辑只在初始化时执行一次

    public enum StatisticItems {
    
        MESSAGES("messages"),
        VIEWS("views");
        final String asString;
    
        StatisticItems(String localised) {
            asString = getLocalizedMsg(localised + ".title");
        }
    
        @Override
        public String toString () {
            return asString;
        }
    
        private static String BUNDLE_NAME = "messages";
        private static final Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
        private static final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_NAME, locale);
    
        private static String getLocalizedMsg(String key) {
            String resourceString;
            try {
                resourceString = bundle.getString(key);
            } catch (MissingResourceException e) {
                return key;
            }
    
            if (arguments == null) {
                return resourceString;
            }
            MessageFormat format = new MessageFormat(resourceString, locale);
            return format.format(arguments);
        }
    }
    

    Downvoter,为什么是downvote?让
    toString()
    方法复杂到当您试图打印调试消息时可能会抛出异常,这似乎是个坏主意。在将来与JSF相关的问题中,您最好不要标记[java]。没有一个回答者考虑到
    FacesContext
    ,这使得两个答案在JSF上下文中在技术上都是错误的。而且,您最好在codereview.se发布代码审阅请求,而不是在SO。或者至少从问题中消除主观性/论证性(包括“最佳实践”等词语)。要获得真正的答案,请在这里使用三个简单的关键字“jsf”、“enum”、“localization”进行搜索。我以前已经回答过这类问题。这里不需要基于每个值进行重写—只需在构造函数中私有消息名,将其存储在字段中,然后在单个实现中使用它,就会更简洁。1。你说我可以为每种情况覆盖toString是什么意思?你不是想试试(统计学家)吗?谢谢@JonSkeet。答案已更新。用户3663882,请参阅第1.2项上的链接。更优雅的做法是将本地化从模型完全移动到视图。这绝对不是模特的责任。@BalusC,我没有想到这一点,但我100%同意。在答案的底部添加了一句话。我不确定是否需要将所有复杂的逻辑放在costructor中,在这种情况下,包括在costructor中加载ResourceBundle(更不用说枚举构造函数了,因为它们是在类加载时执行的)。例如,请参阅。@aioobe-如果这看起来有点太重,那么后面会有各种机制来执行它,例如s。哦,请不要。语言环境是在这个特定的上下文中基于HTTP请求/JSF视图的,这肯定不是应用程序范围。将来,在作为答案进行之前,请亲自测试代码。@BalusC-该代码是从OP复制的。我所做的只是使其成为
    static final
    。但我同意语言环境应该来自上下文。嗯?OP在threadlocal的基础上做得很好,但您将其设置为常量并引入了一个潜在的NPE。
    public enum StatisticItems {
    
        MESSAGES("messages"),
        VIEWS("views");
        final String asString;
    
        StatisticItems(String localised) {
            asString = getLocalizedMsg(localised + ".title");
        }
    
        @Override
        public String toString () {
            return asString;
        }
    
        private static String BUNDLE_NAME = "messages";
        private static final Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
        private static final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_NAME, locale);
    
        private static String getLocalizedMsg(String key) {
            String resourceString;
            try {
                resourceString = bundle.getString(key);
            } catch (MissingResourceException e) {
                return key;
            }
    
            if (arguments == null) {
                return resourceString;
            }
            MessageFormat format = new MessageFormat(resourceString, locale);
            return format.format(arguments);
        }
    }