如何在编译时确保枚举开关的完整性?

cev*_*ing 38 java

我有几个switch语句测试一个enum.enum必须通过switch语句在语句中处理所有值case.在代码重构期间,可能会发生enum收缩和增长.当enum收缩时,编译器会抛出错误.但是,如果enum增长,则不会抛出任何错误.匹配状态被遗忘并产生运行时错误.我想将此错误从运行时移动到编译时.从理论上讲,应该可以enum在编译时检测丢失的情况.有没有办法实现这个目标?

问题已经存在" 如何检测新值已添加到枚举中并且未在交换机中处理 "但它不包含仅与Eclipse相关的解决方案的答案.

shm*_*sel 20

Effective Java中,Joshua Bloch建议创建一个为每个常量实现的抽象方法.例如:

enum Color {
    RED   { public String getName() {return "Red";} },
    GREEN { public String getName() {return "Green";} },
    BLUE  { public String getName() {return "Blue";} };
    public abstract String getName();
}
Run Code Online (Sandbox Code Playgroud)

这将作为安全开关,如果添加新常量,则强制您实现该方法.

编辑:为了消除一些困惑,这里使用常规的等价物switch:

enum Color {
    RED, GREEN, BLUE;
    public String getName() {
        switch(this) {
            case RED:   return "Red";
            case GREEN: return "Green";
            case BLUE:  return "Blue";
            default: return null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 好的,这是可能的(我试过它并且它有效)但是如果我有多个开关,我会从中央`enum`类中的不同位置移动不相关的代码.它工作但代码不属于那里. (4认同)

Oli*_*rth 10

我不知道标准的Java编译器,但Eclipse编译器当然可以配置为警告这个.转到Window-> Preferences-> Java-> Compiler-> Errors/Warnings/Enum type constant on switch.


小智 7

另一种解决方案使用功能方法.您只需要根据下一个模板声明枚举类:

public enum Direction {

    UNKNOWN,
    FORWARD,
    BACKWARD;

    public interface SwitchResult {
        public void UNKNOWN();
        public void FORWARD();
        public void BACKWARD();
    }

    public void switchValue(SwitchResult result) {
        switch (this) {
            case UNKNOWN:
                result.UNKNOWN();
                break;
            case FORWARD:
                result.FORWARD();
                break;
            case BACKWARD:
                result.BACKWARD();
                break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你尝试使用它至少没有一个枚举常量,你将得到编译错误:

getDirection().switchValue(new Direction.SwitchResult() {
    public void UNKNOWN() { /* */ }
    public void FORWARD() { /* */ }
    // public void BACKWARD() { /* */ } // <- Compilation error if missing
});
Run Code Online (Sandbox Code Playgroud)

  • 这将 `n` `switch` 语句减少为 1 个 `switch` 语句。这不是一个完美的解决方案,而是一个很大的改进。但是我认为调用`SwitchResult``Directable`和`switchValue``direct`可能会更好,因为我不认为这个解决方案可以抽象成模板。 (2认同)

Itc*_*chy 1

自 Java 14(带有JEP 361)以来,现在有Switch 表达式可以让您做到这一点。例如以下示例:

public enum ExampleEnum {A, B}

public static String exampleMethod(ExampleEnum exampleEnum) {
    return switch (exampleEnum) {
        case A -> "A";
        case B -> "B";
    };
}
Run Code Online (Sandbox Code Playgroud)

如果添加新的枚举值,C则会出现编译错误:java: the switch expression does not cover all possible input values

但请注意,这并不神奇适用于“正常”(旧) switch语句,例如:

public static String badExampleMethod(ExampleEnum exampleEnum) {
    switch (exampleEnum) {
        case A:
            return "A";
        case B:
            return "B";
    }
}
Run Code Online (Sandbox Code Playgroud)

这已经会引发编译错误:java: missing return statement因此强制您添加一个default分支(然后在添加新的枚举值时不会带来编译错误)。