如何检测新值已添加到枚举中并且未在开关中处理

Posted

技术标签:

【中文标题】如何检测新值已添加到枚举中并且未在开关中处理【英文标题】:How to detect a new value was added to an enum and is not handled in a switch 【发布时间】:2011-04-29 08:01:52 【问题描述】:

有时我必须在我的项目中为枚举类型添加一个新值。

public enum Day 
  SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, 
   FILENOTFOUND //this one is new one

我想要的是对于我拥有的每个未处理新值的开关都有一个编译时错误,就像这个:

switch (color) 
        case MONDAY: 
        case TUESDAY: 
        case WEDNESDAY: 
        case THURSDAY: 
                    System.out.println("Mondays are bad.");
                     break;

        case FRIDAY: System.out.println("Fridays are better.");
                     break;

        case SATURDAY:
        case SUNDAY: System.out.println("Weekends are best.");
                     break;
     

有一个默认值:抛出一些异常还不够好,我希望它是编译时间。

我不认为这是可能的,但也许有人有一个巧妙的技巧......

我以为 Findbugs 会有一个规则来找到这些,但我只看到了这个: Eq: Covariant equals() method defined for enum (EQ_DONT_DEFINE_EQUALS_FOR_ENUM)

编辑:我选择 Mark 的回复,我确实使用 Eclipse,这听起来就像我需要的一样!我根本不是 findbugs 方面的专家,所以我可能错过了这样的功能,尽管我不这么认为。

【问题讨论】:

在枚举声明附近添加注释:-) +1 用于将 FILENOTFOUND 添加到一组不相关的枚举常量中 +0 用于将 FILENOTFOUND 添加到一组不相关的枚举常量中。为什么人们仍然觉得这很有趣? (我不介意 OP 或任何人在临时示例中使用它,但老实说,即使在看到此参考资料 8000 次之后,人们仍然认为这很有趣并相应地投赞成票?) 顺便说一句,+1 是个好问题。 my + 1 也是一个好问题。冷静下来,呼吸一下。 【参考方案1】:

Eclipse 有一个可以启用的编译时警告/错误:“开关”上未覆盖枚举常量。

从您的项目属性(或一般首选项)中,转到 Java 编译器->错误/警告,检查 启用项目特定设置。您会在潜在的编程问题下找到警告。默认设置为 Ignore,但您可以将其设置为 WarningError

编辑:我认为这是不言而喻的,但我想我还是会说:这仅适用于您在 Eclipse 中开发或将其用于构建管理的情况。显然 Findbugs 或类似的等价物将是“真正的”答案,因为它超越了 IDE 并且可以集成到构建过程中。

【讨论】:

让我吃惊的是 Eclipse 有这个功能,而 Findbugs 没有。 @rsp:他们呢?如果它们是通过 eclipse 编译的,这将捕获它们。如果它们不在您的控制之下,显然您无法捕捉到这些错误,但其他任何东西都不会。例如。如果它是一个分布式库 jar,您是否希望看到来自使用您的 jar 的所有 800,000 个客户端的错误消息?显然你需要控制你的罐子才能找到它。他要求编译错误,这意味着他正在编译它 @Mark Peters,我的观点是,IDE 功能不会使包含枚举开关的 cient 代码对更改具有鲁棒性,除非针对新版本重新编译它们。当客户端代码记录未处理的案例时,它确实有帮助。 @rsp:当然,但这不是 OP 要求的。他要求一个编译时错误,这显然意味着他将要重新编译客户端代码。 我认为我们也在这里帮助人们创建更好的代码,即使建议不是他们所要求的。【参考方案2】:

您可以通过添加默认子句并在访问时记录来做到这一点:

switch (color) 
default:
    log.error("Unknown color in switch: " + color);
    break

case MONDAY: /*FALLTHROUGH*/
case TUESDAY: 

(添加 fallthrough cmets 可以帮助以后的维护人员确定您是否忘记了代码 :-))

编辑从 cmets 复制的关于马克回答的澄清:

这样的 IDE 功能信号案例在更改时对开发人员来说很好,但它不会捕获您的代码所依赖的其他代码部分的更改。

除非针对新版本重新编译它们,否则它不会使包含枚举开关的 cient 代码对更改具有鲁棒性。

当客户端代码记录未处理的案例时,它确实有帮助;部署的代码并不总是可以完全控制其类路径或其中的库版本。

【讨论】:

这是 OP 要求的编译时检查? 非编译时使用受限,不适用于问题。编辑:删除了 d/v,这仍然有用,所以我不能称之为“错误”。 @Kirk Woll,不,不是。即使您不重新编译包含开关的代码,使用此模式也可以使您的代码更健壮地抵抗对使用的类/枚举的更改。我认为这是一个更好的选择,即使您的 IDE 确实支持这种类型的检查,也可以确保您不会错过这种情况。 如果运行时是路由,这可能是断言或类似的良好候选;在构建生产代码时可以删除的东西。 @Mark,我的部分观点是这样的检查应该出现在生产代码中,而不仅仅是在开发/测试/验收阶段。【参考方案3】:

IntelliJ 是一种检查,并非所有大小写都已设置。它有一个自动修复来填补缺失的案例。

【讨论】:

以上是关于如何检测新值已添加到枚举中并且未在开关中处理的主要内容,如果未能解决你的问题,请参考以下文章

即使原始模型中未指定新值,如何将新值添加到现有 MongoDB 数据库中

在 SQL 中检测到重叠,未在选择中使用子查询且未将重复记录添加到结果集中

Camelot 未在表中检测到表

开关盒错误?

如何在 ASP .NET MVC 5 中使用 select2 将新值动态添加到列表框并将其传递给控制器​​?

如何在 iOS 上检测指南针校准开关状态