【问题标题】:I'm prevented from using a switch statement that doesn't cover all possible cases我被阻止使用不涵盖所有可能情况的 switch 语句
【发布时间】:2021-04-18 03:12:07
【问题描述】:
return degrees % 90 != 0? Optional.empty() : Optional.of( switch( degrees ) {
            case 0 -> NORTH;
            case 90 -> EAST;
            case 180 -> SOUTH;
            case 270 -> WEST;
            //default -> null;  is there something I can put here to make empty Optional?
        } );

Above 返回一个 Optional 包含基本方向的枚举。该代码之前已确保这些是degrees 仅有的 4 个可能值。但 IntelliJ IDEA 不允许这样做,抱怨 switch 没有处理所有可能的值。 我已经搜索了 @SuppressWarnings 注释来允许这样做;我找到的最接近的是SwitchStatementWithoutDefaultBranch,但它没有帮助。

似乎应该有一个注释可以允许这样做。

我知道可以重写代码来解决这个问题,但是为什么不能处理呢?

【问题讨论】:

  • 去掉三元只用Optional.ofNullable?
  • case 270改成default?
  • 太棒了!谢谢你。 (我正在将您的解决方案添加到我即将写的答案中。)但是,我仍然认为应该有一个 @SuppressWarnings 注释来允许这样做。

标签: java intellij-idea switch-statement optional


【解决方案1】:

有两种不同的开关结构。 switch 表达式和 switch 语句。 switch 表达式是相当新的(JDK 中添加的,嗯,14?不到 2 年前)。另一方面,switch 语句形式已有 25 年以上的历史。

switch 语句表单具有许多 linting 工具和 IDE 会在您没有涵盖所有情况时生成警告的属性。

但是,这是关键,您使用的是 switch 表达式形式,Java 规范要求编译器可证明的详尽性

换句话说,对于 switch 语句,不详尽是好的,而不是错误,甚至不是 javac-spec-enforced 警告,但大多数 linter/IDE 都会对此发出警告,但您使用的是 switch 表达式形式。规范说这里必须产生一个错误。没有 @SuppressWarnings 或任何其他可让 intellij 忽略规范要求的 intellij 设置。

原因很简单:您将此开关用作表达式,那么如果没有遇到任何 case 块,编译器应该假定该开关解析为什么?

如果您说:但这不可能发生 - 好吧,编译器不知道这一点,并且可能会发生疯狂的事情。充其量你会假设编译器会抛出一些东西,但是,规范说它不是这样工作的。

【讨论】:

  • 有趣。感谢您的澄清。
  • 当然,如果你对在这种情况下扔东西的想法没意见,你可以精确地插入那个,.i.e. default -> throw something;.
  • 我认为 default 案例必须产生一个值(与其他案例一样),并且不能是像 throw.. 这样的语句。这就是 Optional.ofnullable(...) 与 @987654326 一起工作的原因@
  • @RobertLewi 不正确。 default -> throw... 在 switch 表达式中是合法的。试试看。
【解决方案2】:

这里不需要三元运算符。如果你传入nullOptional.ofNullable 会给你一个Optional.empty(),所以你可以这样做:

return Optional.ofNullable( switch( degrees ) {
            case 0 -> NORTH;
            case 90 -> EAST;
            case 180 -> SOUTH;
            case 270 -> WEST;
            default -> null;
        } );

【讨论】:

  • 太棒了!但是,我仍然认为应该有一个 @SuppressWarnings 选项来允许这样做。
  • @RobertLewis 如果degrees是360,它会通过degrees % 90 != 0检查,然后进入开关,你会返回什么?
  • @RobertLewis 好吧,Java 不能(不够聪明)验证代码的如此复杂的语义。它也不能相信你的话,因为 Java 试图成为一种 安全 语言。如果你看一下近年来出现的功能。而不是@SuppressWarnings,我宁愿用某种方式来指定代码的语义,以便编译器可以推理它:)
  • @RobertLewis 当您认为不可能达到这一点时,您可以随时写default -> throw new AssertionError();。这正是编译器在证明详尽无遗时生成的内容,例如当切换一个类型的所有enum 常量时。它不允许缺少这样的默认代码。
  • @RobertLewis 抛出异常的语句在 switch 表达式中是允许的,因为它们仍然满足没有值不返回的要求(它们根本不返回)。这不是什么新鲜事,例如您可以让值兼容的 lambda 表达式引发异常,例如Optional.empty().map(x -> { throw new AssertionError("should never reach here"); });。对于 switch 表达式,它被认为很常见,你甚至可以省略大括号,就像在我的 default -> throw new AssertionError(); 示例中一样,使其与返回单个表达式的值一样简洁。
猜你喜欢
  • 2021-12-29
  • 1970-01-01
  • 2014-11-23
  • 2022-10-07
  • 2020-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
相关资源
最近更新 更多