Java的枚举和切换语句 – 默认情况下?

对于build议抛出exception的人:
抛出exception不会给我一个编译时错误,它给我一个运行时错误。 我知道我可以抛出一个exception,我宁愿在编译期间比在运行时死亡。

首先,我使用Eclipse 3.4。

我有一个数据模型有一个模式属性是一个枚举。

enum Mode {on(...), off(...), standby(...); ...} 

我目前正在写这个模型的视图,我有代码

 ... switch(model.getMode()) { case on: return getOnColor(); case off: return getOffColor(); case standby: return getStandbyColor(); } ... 

我得到一个错误“此方法必须返回typesjava.awt.Color的结果”,因为我没有默认情况下,并没有返回xxx在函数结束。 想要一个编译错误的情况下,有人添加另一种types的枚举(例如closures),所以我不想把一个默认情况下抛出一个AssertionError,因为这将编译与修改后的模式,而不是被视为错误直到运行时。

我的问题是这样的:
为什么EclipseBuilder(和javac)不能识别这个开关覆盖了所有的可能性(或覆盖了它们?),并停止警告我需要返回types。 有没有办法,我可以做我想要的,而不添加方法模式?

如果没有,那么是否有一个选项可以在switch语句上警告/错误,而这些语句并不包含所有Enum的可能值?

编辑:罗布:这是一个编译错误 。 我只是试着用javac编译它,然后我得到一个针对方法最后一个“丢失的返回语句”的错误。 Eclispe只是将错误放在方法的顶部。

你总是可以使用Enum with Visitor模式:

 enum Mode { on { public <E> E accept( ModeVisitor<E> visitor ) { return visitor.visitOn(); } }, off { public <E> E accept( ModeVisitor<E> visitor ) { return visitor.visitOff(); } }, standby { public <E> E accept( ModeVisitor<E> visitor ) { return visitor.visitStandby(); } } public abstract <E> E accept( ModeVisitor<E> visitor ); public interface ModeVisitor<E> { E visitOn(); E visitOff(); E visitStandby(); } } 

然后你会实现如下的东西:

 public final class ModeColorVisitor implements ModeVisitor<Color> { public Color visitOn() { return getOnColor(); } public Color visitOff() { return getOffColor(); } public Color visitStandby() { return getStandbyColor(); } } 

你会使用它如下:

 return model.getMode().accept( new ModeColorVisitor() ); 

这是更详细的,但如果一个新的枚举被声明,你会立即得到一个编译错误。

您必须在Eclipse中启用(窗口 – >首选项)设置“Enum type constant not in switch”(包含错误级别)。

在方法的末尾抛出exception,但不要使用默认情况。

 public String method(Foo foo) switch(foo) { case x: return "x"; case y: return "y"; } throw new IllegalArgumentException(); } 

现在,如果有人在后来添加新的案例,Eclipse会让他知道他错过了一个案例。 所以不要使用默认值,除非你有足够的理由这样做。

我不知道为什么你会得到这个错误,但这里有一个build议,你为什么不定义在枚举本身的颜色? 那么你不能不小心忘记定义一个新的颜色。

例如:

 import java.awt.Color; public class Test { enum Mode { on (Color.BLACK), off (Color.RED), standby (Color.GREEN); private final Color color; Mode (Color aColor) { color = aColor; } Color getColor() { return color; } } class Model { private Mode mode; public Mode getMode () { return mode; } } private Model model; public Color getColor() { return model.getMode().getColor(); } } 

顺便说一句,这里是比较原始的情况下,与编译器错误。

 import java.awt.Color; public class Test { enum Mode {on, off, standby;} class Model { private Mode mode; public Mode getMode () { return mode; } } private Model model; public Color getColor() { switch(model.getMode()) { case on: return Color.BLACK; case off: return Color.RED; case standby: return Color.GREEN; } } } 

我会说这可能是因为model.GetMode() 可能会返回null。

创build引发exception的默认情况:

 throw new RuntimeExeption("this code should never be hit unless someone updated the enum") 

…这几乎描述了为什么Eclipse抱怨:虽然你的交换机可能涵盖所有的枚举案例今天,有人可以添加一个案件,而不是明天重新编译。

为什么EclipseBuilder没有意识到这个开关覆盖了所有的可能性(或者它覆盖了它们?)并停止警告我需要返回types。 有没有办法,我可以做我想要的,而不添加方法模式?

在Eclipse中这不是问题,而是编译器javac 。 所有javac看到的是,在没有任何东西匹配的情况下,你没有返回值(事实上, 知道你是匹配所有情况是无关紧要的)。 你必须在默认情况下返回一些东西 (或抛出exception)。

就个人而言,我只是抛出一些例外。

你的问题是,你正试图使用​​switch语句作为你的枚举被locking的指标。

事实是,'switch'语句和java编译器不能识别你不想让你的枚举中的其他选项。 在你的枚举中只需要三个选项的事实与你devise的switch语句是完全分开的,正如别人所指出的那样,总是有一个默认语句。 (在你的情况下,它应该抛出一个exception,因为这是一个未处理的情况。)

你应该自由地在你的枚举中加上注释,这样每个人都知道不要碰它,而且你应该修改你的switch语句来为不可识别的情况抛出错误。 这样你就覆盖了所有的基础。

编辑

抛出编译器错误的问题。 这不是严格意义上的。 你有一个枚举有三个选项,一个开关有三个选项。 你想要它抛出一个编译器错误,如果有人添加一个值的枚举。 除了枚举可以是任何大小,所以如果有人改变编译器的错误是没有意义的。 此外,您正在定义您的枚举的大小基于switch语句可能位于一个完全不同的类。

Enum和Switch的内部工作是完全独立的,应该保持解耦。

一个好的方法是添加默认情况下返回一些错误值或抛出exception,并使用jUnit自动化testing,例如:

 @Test public void testEnum() { for(Mode m : Mode.values() { m.foobar(); // The switch is separated to a method // If you want to check the return value, do it (or if there's an exception in the // default part, that's enough) } } 

当你进行自动化testing时,这将为所有枚举定义foobar。

既然我不能评论…

  1. 始终,始终,始终有一个默认情况。 你会惊奇地发现它会被“频繁”击中(Java比Cless,但仍然)。

  2. 话虽如此,如果我只想在我的情况下只处理/closures。 您的javac语义处理将标记为一个问题。

现在(这个答案是在原始问题后几年写的),eclipse允许在Window – > Preferences – > Java – > Compiler – > Error / warnings – > Potential programming problems中进行以下configuration:

不完整的开关情况

即使存在默认情况,也是信号