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

2022-08-31 16:48:50

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

首先,我使用的是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类型的结果”,因为我没有默认大小写,并且在函数末尾没有返回xxx。我希望在有人向枚举中添加另一种类型(例如关闭)的情况下出现编译错误,因此我不想放置一个抛出AssersisError的默认情况,因为这将使用修改后的Mode进行编译,并且在运行时之前不会被视为错误。

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

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

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


答案 1

您始终可以使用 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() );

这要详细得多,但是如果声明了新的枚举,您将立即收到编译错误。


答案 2

您必须在 Eclipse(窗口 -> 首选项)中启用“枚举类型常量未包含在交换机中”设置,并带有错误级别。

在方法的末尾引发异常,但不要使用默认大小写。

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

  throw new IllegalArgumentException();
}

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