Java 枚举和 Switch 语句 - 默认情况?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/859563/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Enums and Switch Statements - the default case?
提问by KitsuneYMG
For people suggesting throwing an exception:
Throwing an exception doesn't give me a compile-time error, it gives me a runtime error. I know I can throw an exception, I'd rather die during compilation than during runtime.
对于建议抛出异常的人:
抛出异常不会给我一个编译时错误,它会给我一个运行时错误。我知道我可以抛出异常,我宁愿在编译期间死亡而不是在运行时死亡。
First-off, I am using eclipse 3.4.
首先,我使用的是 eclipse 3.4。
I have a data model that has a mode property that is an Enum.
我有一个数据模型,它的模式属性是一个枚举。
enum Mode {on(...), off(...), standby(...); ...}
I am currently writing a view of this model and I have the code
我目前正在编写此模型的视图并且我有代码
...
switch(model.getMode()) {
case on:
return getOnColor();
case off:
return getOffColor();
case standby:
return getStandbyColor();
}
...
I am getting an error "This method must return a result of type java.awt.Color" because I have no default case and no return xxx at the end of the function. I wanta compilation error in the case where someone adds another type to the enum (e.g. shuttingdown) so I don't want to put a default case that throws an AssertionError, as this will compile with a modified Mode and not be seen as an error until runtime.
我收到错误消息“此方法必须返回 java.awt.Color 类型的结果”,因为我没有默认情况,也没有在函数末尾返回 xxx。 我想要在有人向枚举添加另一种类型(例如关闭)的情况下出现编译错误,所以我不想放置一个会引发 AssertionError 的默认情况,因为这将使用修改后的模式进行编译而不被视为直到运行时出错。
My question is this:
Why does EclipseBuilder (and javac) not recognize that this switch covers all possibilities (or does it cover them?) and stop warning me about needing a return type. Is there a way I can do what I want without adding methods to Mode?
我的问题是:
为什么 EclipseBuilder(和 javac)没有认识到这个开关涵盖了所有可能性(或者它是否涵盖了它们?)并停止警告我需要返回类型。有没有一种方法可以在不向模式添加方法的情况下做我想做的事?
Failing that, is there an option to warn/error on switch statements that don't cover all of the Enum's possible values?
如果做不到这一点,是否有一个选项可以在不涵盖枚举的所有可能值的 switch 语句上发出警告/错误?
Edit: Rob: It is a compile error. I just tried compiling it with javac and I get a "missing return statement" error targeting the last } of the method. Eclispe just places the error at the top of the method.
编辑:Rob:这是一个编译错误。我只是尝试用 javac 编译它,但我收到了一个针对方法的最后一个 } 的“缺少返回语句”错误。Eclispe 只是将错误放在方法的顶部。
采纳答案by mtpettyp
You could always use the Enum with Visitor pattern:
您始终可以将 Enum 与访问者模式一起使用:
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();
}
}
Then you would implement something like the following:
然后你将实现如下内容:
public final class ModeColorVisitor implements ModeVisitor<Color> {
public Color visitOn() {
return getOnColor();
}
public Color visitOff() {
return getOffColor();
}
public Color visitStandby() {
return getStandbyColor();
}
}
You'd use it as follows:
您可以按如下方式使用它:
return model.getMode().accept( new ModeColorVisitor() );
This is a lot more verbose but you'd immediately get a compile error if a new enum was declared.
这要冗长得多,但如果声明了新的枚举,您会立即收到编译错误。
回答by kdgregory
Create a default case that throws an exception:
创建一个抛出异常的默认情况:
throw new RuntimeExeption("this code should never be hit unless someone updated the enum")
... and that pretty much describes why Eclipse is complaining: while your switch may cover all enum cases today, someone could add a case and not recompile tomorrow.
...这几乎描述了 Eclipse 抱怨的原因:虽然您的开关可能涵盖今天的所有枚举案例,但有人可以添加一个案例而不是明天重新编译。
回答by mipadi
Why does EclipseBuilder not recognize that this switch covers all possibilities (or does it cover them?) and stop warning me about needing a return type. Is there a way I can do what I want without adding methods to Mode?
为什么 EclipseBuilder 没有认识到这个开关涵盖了所有可能性(或者它是否涵盖了所有可能性?)并停止警告我需要返回类型。有没有一种方法可以在不向模式添加方法的情况下做我想做的事?
It's not an issue in Eclipse, but rather the compiler, javac
. All javac
sees is that you don't have a return value in the case in which nothingis matched (the fact that youknow you are matching all cases is irrelevant). You have to return somethingin the default case (or throw an exception).
这不是 Eclipse 中的问题,而是编译器的问题,javac
. 所有javac
看到的是在没有任何匹配的情况下你没有返回值(你知道你匹配所有情况的事实是无关紧要的)。您必须在默认情况下返回某些内容(或引发异常)。
Personally, I'd just throw some sort of exception.
就个人而言,我只是抛出某种异常。
回答by Paul Sonier
I'd say it's probably because model.GetMode() couldreturn null.
我会说这可能是因为 model.GetMode()可能返回 null。
回答by Paul
Since I can't just comment...
因为我不能只评论...
Always, Always, Always have a default case. You'd be surprised how "frequently" it would be hit (Less in Java than C, but still).
Having said that, what if I only want to handle only on/off in my case. Your semantic processing by javac would flag that as an issue.
总是,总是,总是有一个默认情况。你会惊讶于它会“经常”被击中(在 Java 中比 C 少,但仍然如此)。
话虽如此,如果我只想在我的情况下只处理开/关怎么办。javac 的语义处理会将其标记为问题。
回答by DevinB
Your problem is that you are trying to use the switch statement as an indicator that your enum is locked down.
你的问题是你试图使用 switch 语句作为你的枚举被锁定的指示器。
The fact is that the 'switch' statement and the java compiler cannot recognize that you do not want to allow other options in your enum. The fact that you only want three options in your enum is completely separate from your design of the switch statement, which as noted by others should ALWAYS have a default statement. (In your case it should throw an exception, because it is an unhandled scenario.)
事实是,'switch' 语句和 java 编译器无法识别您不想在枚举中允许其他选项。您只需要枚举中的三个选项这一事实与您对 switch 语句的设计完全分开,正如其他人所指出的那样,它应该始终具有默认语句。(在您的情况下,它应该抛出异常,因为这是一个未处理的场景。)
You should liberally sprinkle your enum with comments so that everyone knows not to touch it, and you should fix your switch statement to throw errors for unrecognized cases. That way you've covered all the bases.
您应该在您的枚举中随意添加注释,以便每个人都知道不要碰它,并且您应该修复 switch 语句以在无法识别的情况下抛出错误。这样你就涵盖了所有的基础。
EDIT
编辑
On the matter of throwing compiler error. That does not strictly make sense. You have an enum with three options, and a switch with three options. You want it to throw a compiler error if someone adds a value to the enum. Except that enums can be of any size, so it doesn't make sense to throw a compiler error if someone changes it. Furthermore, you are defining the size of your enum based on a switch statement which could be located in a completely different class.
关于抛出编译器错误的问题。这不是严格意义上的。您有一个包含三个选项的枚举和一个包含三个选项的开关。如果有人向枚举添加值,您希望它抛出编译器错误。除了枚举可以是任何大小之外,因此如果有人更改它,抛出编译器错误是没有意义的。此外,您正在根据可能位于完全不同的类中的 switch 语句定义枚举的大小。
The internal workings of Enum and Switch are completely separate and should remain uncoupled.
Enum 和 Switch 的内部工作是完全独立的,应该保持解耦。
回答by amarillion
I don't know why you get this error, but here is a suggestion, Why don't you define the color in the enum itself? Then you can't accidentally forget to define a new color.
我不知道你为什么会收到这个错误,但这里有一个建议,你为什么不在枚举本身中定义颜色?那么你不能不小心忘记定义一个新的颜色。
For example:
例如:
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();
}
}
btw, for comparison here is the original case, with compiler error.
顺便说一句,为了比较这里是原始情况,编译器错误。
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;
}
}
}
回答by egaga
You have to enable in Eclipse (window -> preferences) settings "Enum type constant not covered in switch" with Error level.
您必须在 Eclipse(窗口 -> 首选项)设置中启用错误级别的“开关中未涵盖的枚举类型常量”。
Throw an exception at the end of the method, but don't use default case.
在方法结束时抛出异常,但不要使用默认情况。
public String method(Foo foo)
switch(foo) {
case x: return "x";
case y: return "y";
}
throw new IllegalArgumentException();
}
Now if someone adds new case later, Eclipse will make him know he's missing a case. So don't ever use default unless you have really good reasons to do so.
现在,如果有人稍后添加新案例,Eclipse 会让他知道他错过了一个案例。所以永远不要使用默认值,除非你有很好的理由这样做。
回答by Touko
A nice way for this would be to add the default case to return some error value or throw exception and to use automated tests with jUnit, for example:
一个很好的方法是添加默认情况以返回一些错误值或抛出异常,并使用 jUnit 进行自动化测试,例如:
@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)
}
}
When you got automated tests, this will take care of that foobar is defined for all enumerations.
当您进行自动化测试时,这将处理为所有枚举定义的 foobar。
回答by pasaba por aqui
Nowadays (this answer is written several years after the original question), eclipse allows following configuration at Window -> Preferences -> Java -> Compiler -> Error/warnings -> Potential programming problems:
如今(这个答案是在原始问题几年后写的),eclipse 允许在 Window -> Preferences -> Java -> Compiler -> Error/warnings -> Potential programming questions 进行以下配置:
Incomplete switch cases
Signal even if default case exists
不完整的开关盒
即使存在默认情况也发出信号