Java 枚举和 Switch 语句 - 默认情况?

发布于 2024-07-19 02:59:59 字数 912 浏览 2 评论 0原文

对于建议抛出异常的人:
抛出异常不会给我带来编译时错误,它会给我带来运行时错误。 我知道我可以抛出异常,我宁愿在编译期间死也不愿在运行时死。

首先,我使用的是 eclipse 3.4。

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

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

我目前正在编写此模型的视图,并且我有代码,但

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

我收到错误“此方法必须返回 java.awt.Color 类型的结果”,因为我没有默认情况,并且函数末尾没有 return xxx 。 想要在有人向枚举添加另一种类型(例如关闭)的情况下出现编译错误,因此我不想放置抛出 AssertionError 的默认情况,因为这将编译使用修改后的模式,直到运行时才被视为错误。

我的问题是这样的:
为什么 EclipseBuilder(和 javac)不认识到这个开关涵盖了所有可能性(或者它涵盖了它们?)并停止警告我需要返回类型。 有没有办法可以在不向模式添加方法的情况下做我想做的事情?

如果做不到这一点,是否有一个选项可以对未涵盖所有枚举可能值的 switch 语句发出警告/错误?

编辑: Rob:这是一个编译错误。 我只是尝试用 javac 编译它,并且针对该方法的最后一个 } 出现“缺少返回语句”错误。 Eclispe 只是将错误放在方法的顶部。

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.

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 want a 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.

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?

Failing that, is there an option to warn/error on switch statements that don't cover all of the Enum's possible values?

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

三生池水覆流年 2024-07-26 02:59:59

您始终可以将枚举与访问者模式一起使用:

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

这更加冗长,但如果声明了新的枚举,您会立即收到编译错误。

You could always use the Enum with Visitor pattern:

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.

甜味拾荒者 2024-07-26 02:59:59

您必须在 Eclipse(窗口 -> 首选项)设置中启用“开关中未涵盖的枚举类型常量”和错误级别。

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

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

  throw new IllegalArgumentException();
}

现在,如果有人稍后添加新案例,Eclipse 会让他知道他错过了一个案例。 因此,除非您有充分的理由,否则永远不要使用默认值。

You have to enable in Eclipse (window -> preferences) settings "Enum type constant not covered in switch" with Error level.

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.

撑一把青伞 2024-07-26 02:59:59

我不知道你为什么会收到此错误,但这里有一个建议,为什么不在枚举本身中定义颜色? 这样您就不会意外忘记定义新颜色。

例如:

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

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;
        }
    }   
}
素染倾城色 2024-07-26 02:59:59

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

I'd say it's probably because model.GetMode() could return null.

掩于岁月 2024-07-26 02:59:59

一个很好的方法是添加默认情况以返回一些错误值或抛出异常,并使用 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)
  }
}

当您进行自动化测试时,这将处理为所有枚举定义的 foobar 。

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:

@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.

怕倦 2024-07-26 02:59:59

创建一个抛出异常的默认情况:

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

...这几乎描述了 Eclipse 抱怨的原因:虽然您的开关可能涵盖今天的所有枚举情况,但有人可能会添加一个情况而不是明天重新编译。

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.

帥小哥 2024-07-26 02:59:59

为什么 EclipseBuilder 不认识到这个开关涵盖了所有可能性(或者它涵盖了它们?)并停止警告我需要返回类型。 有没有办法可以在不向模式添加方法的情况下做我想做的事情?

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

就我个人而言,我只会抛出某种异常。

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?

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 nothing is matched (the fact that you know you are matching all cases is irrelevant). You have to return something in the default case (or throw an exception).

Personally, I'd just throw some sort of exception.

执笔绘流年 2024-07-26 02:59:59

您的问题是您试图使用 switch 语句作为您的枚举已锁定的指示器。

事实上,“switch”语句和 java 编译器无法识别您不想在枚举中允许其他选项。 事实上,您只需要枚举中的三个选项与您的 switch 语句的设计完全分开,正如其他人指出的那样,它应该始终有一个默认语句。 (在你的情况下,它应该抛出一个异常,因为这是一个未处理的场景。)

你应该在你的枚举上随意添加注释,以便每个人都知道不要碰它,并且你应该修复你的 switch 语句,以针对无法识别的情况抛出错误。
这样你就涵盖了所有的基础。

编辑

关于抛出编译器错误的问题。 这严格来说没有意义。 您有一个包含三个选项的枚举,以及一​​个包含三个选项的开关。 如果有人向枚举添加值,您希望它抛出编译器错误。 除了枚举可以是任意大小之外,因此如果有人更改它,抛出编译器错误是没有意义的。 此外,您根据 switch 语句定义枚举的大小,该语句可能位于完全不同的类中。

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

Your problem is that you are trying to use the switch statement as an indicator that your enum is locked down.

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.)

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.

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.

The internal workings of Enum and Switch are completely separate and should remain uncoupled.

a√萤火虫的光℡ 2024-07-26 02:59:59

因为我不能只是发表评论...

  1. 总是,总是,总是有一个默认情况。 你会惊讶于它被命中的“频率”(在 Java 中比 C 中少,但仍然如此)。

  2. 话虽如此,如果我只想处理我的情况下的开/关怎么办? javac 的语义处理会将其标记为一个问题。

Since I can't just comment...

  1. Always, Always, Always have a default case. You'd be surprised how "frequently" it would be hit (Less in Java than C, but still).

  2. 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.

清醇 2024-07-26 02:59:59

如今(这个答案是在原始问题几年后写的),eclipse 允许在 Window -> 进行以下配置: 首选项-> Java-> 编译器-> 错误/警告 -> 潜在的编程问题:

不完整的开关案例

<块引用>

即使存在默认情况也会发出信号

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:

Incomplete switch cases

Signal even if default case exists

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文