【问题标题】:Using Case Statements使用案例陈述
【发布时间】:2012-07-26 15:01:54
【问题描述】:

我使用 int[] 数组作为参考。我想知道我对 case 语句的使用是否合理,或者它是否会导致错误。

这是我的代码:

    int switcheroo = intarray[0];
    int foo = intarray[1];
    boolean size = false; 
    boolean biggersize = false;

    switch (switcheroo) {

    case 0:
        switch (foo) {
        case 1:
            doSomething(switcheroo); //change switcheroo somehow.
            break;
        case 2: 
            doSomethingElse(switcheroo); //change switcheroo differently.
            break;
        }
    case 1:
        size = true;
        break;
    case 2: 
        biggersize = true;
        break;
    default:
        break;
    }

除非是巧合,否则这会按照我的意愿将嵌套 case 语句的更改影响到其他 case。

我的问题是:

这种嵌套是否会导致进一步的麻烦?

是否缺少休息;在一个案例不好的做法之后?

谢谢。

编辑:在 switch 语句中间更改 switcheroo 的方法被放在那里以响应该问题。我不会这样做这是我的程序。

【问题讨论】:

  • 这被广泛认为是一种不好的做法,是的。 break 基本上是一个 goto,使控制流难以遵循。
  • doSomething(switcheroo); //change switcheroo somehow. => 你不能在那个方法中改变switcheroo。并且在开关中间更改开关变量的值看起来不是一个好主意。
  • @millimoose 对所有 case 语句不使用 break 有时被认为是一种不好的做法,但绝不是“使用 break" a bad practice because it's a goto." break` 和 continue 已确定成为goto 的唯一合法用途,这就是它们存在于语言中的原因。
  • @SeanKenny 不,我会直截了当地说。
  • 否:break 不是一个好主意。它只留下嵌套代码。需要中断开关以停止开关解析。

标签: java switch-statement


【解决方案1】:

嵌套不会完全造成麻烦,但它可能会令人困惑。添加 cmets 和/或其他文档将真正帮助未来的编码人员(以及您自己在一周内!)通过查看来理解这一点。

没有休息本身并不是一个坏习惯,但这是大多数情况下的陈述,所以我会在末尾添加一条评论,如// no break, allow fall-through

所以这两种情况都归结为良好的文档。

这些点与我不认为这段代码做你认为它会做的事情是垂直的。

case 子句不会在您每次遇到时都重新评估 - 它们只是跳转到切换的点。因此,在您的示例中,如果您从 case 0 开始,您将总是case 1 结束 - 您永远不会从 case 0case 2 结束。

如果我要重组它,我会这样做。我不会使用int,而是使用enum

enum Foo { GOOD_FOO, BAD_FOO }
enum Switcharoo { BAR, BAZ, BAQ, ESCAPE }
enum Size { NONE, REGULAR, BIGGER }

Foo foo = ... // assigned somewhere
Switcharoo roo = ... // assigned somewhere
Size size = NONE;

// use a while loop to reevalulate roo with each pass
while(roo != Switcharoo.ESCAPE) {
    switch(roo){
        case BAR:
                switch(foo) {
                    case GOOD_FOO: foo = doSomething(foo); break;
                    case BAD_FOO: foo = doSomethingElse(foo); break;
                }
            break;
        case BAZ:
            roo = Switcharoo.ESCAPE;
            size = Size.REGULAR;
            break;
        case BAQ:
            roo = Switcharoo.ESCAPE;
            size = Size.BIGGER;
            break;

    }
}

【讨论】:

  • +1 - “你永远不会从案例 0 到案例 2” 这似乎得出了一个结论:每次你让事情变得比他们应该的更复杂, 拐角处有个 bug ;-)
  • @corsiKa 如果我在嵌套开关中添加了默认情况,这会被无意中省略,是否会触发外部开关中的情况 2?
  • @Sean 不。无论如何,案例 0 将始终落入案例 1。将实际语句视为一个大页面,将case 0 语句视为便笺。当您进行切换时,您会转到便笺,并继续前进,直到您点击break。向内部开关添加一个中断只会退出该开关,您将再次处于案例 0 的末尾,并将继续进行案例 1。
【解决方案2】:

RE:是缺少休息;在一个案例不好的做法之后?

如果您在每个 case 语句后不包含中断,则流程将继续通过下一个语句,因此将执行多个选项的代码。

来自 Java 教程:

另一个有趣的地方是break语句。每个中断语句 终止封闭的 switch 语句。控制流程继续 switch 块之后的第一条语句。中断语句 是必要的,因为没有它们,switch 块中的语句就会下降 through:匹配case标签后的所有语句都在 序列,无论后续案例标签的表达如何, 直到遇到 break 语句。

查看http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html 了解有关 switch 语句的更多详细信息。

【讨论】:

  • 这是否意味着如果在外部语句中触发了case 0,那么无论嵌套的switch语句之后的switcheroo的值如何,case 1都会一直跟随?
  • 确实如此,@SeanKenny,案例 0 将始终导致案例 1 也被执行。并且从案例 0 或案例 1 永远不会到达案例 2(外部)。
  • 是的,会执行外层switch的case 1。它将继续设置 size=true 并且由于中断而退出外壳。根据 foo 的值,内部开关将仅执行 case 1 或 2。
  • 尝试使用双重调度来简化你的代码。在 15 多年的 Java 编程中,我从未在开关中使用过开关......
【解决方案3】:

如果foo既不是1也不是2,switcheroo是否应该继续case 1?如果是,那么您的代码是正确的。如果没有,需要在case 1之前加一个break

【讨论】:

    【解决方案4】:

    switch 运算符是一种条件if 运算符。一堆 if 运算符可能会报告说您需要在代码中涉及对象多态性,而不是创建连续的 if-switch 运算符。

    考虑将数据重新排列到类/对象中,并使用多态方法处理它们。它将使您的代码更可靠、更易于管理且更美观。

    【讨论】:

      【解决方案5】:

      我不确定我是否理解你的第一个问题,你能给我一些更多的信息(可能是具体的)吗?

      关于第二个问题,case后面没有break语句没有错,只要你知道代码会继续执行直到找到break语句。

      【讨论】:

        【解决方案6】:

        好吧..您似乎唯一缺少的是可读性。只有在迫不得已的情况下才进行这种嵌套。

        Is the lack of a break; after a case bad practice?
        

        还不错,避免异常行为是一种好习惯。如果没有此 Break,您的代码将继续执行到您的最后一个案例。

        在你的第一个外壳中添加 break。

        【讨论】:

          【解决方案7】:

          我建议避免结合使用嵌套和直通。至少就个人而言,我倾向于期望每个case 都以break 结尾,所以我只会在它很容易发现并且导致比if..else 更清晰的代码的情况下使用fallthrough,例如:

          switch (foo) {
              case 0:
              case 1:
                  doSomething();
                  break;
          
              case 2:
                  doSomethingElse();
                  break;
          
              default:
                  break;
          }
          

          也就是说,无论是空的还是非常简单的(一个语句)case 主体。在您的情况下,将第一个 case 的主体重构为一个方法可能会起作用:

          void changeSwitcheroo(int foo, int switcheroo) {
              switch (foo) {
                  case 1:
                      doSomething(switcheroo); //change switcheroo somehow.
                      break;
                  case 2: 
                      doSomethingElse(switcheroo); //change switcheroo differently.
                      break;
              }
          }
          
          // ...
          
          int switcheroo = intarray[0];
          int foo = intarray[1];
          
          switch (switcheroo) {
              case 0:
                  changeSwitcheroo(foo, switcheroo);
              case 1:
                  size = true;
                  break;
              case 2: 
                  biggersize = true;
                  break;
              default:
                  break;
          }
          

          (这主要是在争论可读性和风格。switch的含义仍然是“如果switcheroo是1,则跳转到case0的中间。)

          【讨论】:

          • 我认为default 不需要break;)
          • @Nandkumar 可能没有,但我对编码器强迫症的看法趋向于拥有它。
          【解决方案8】:

          如果只有 2 个备选方案,请选择 if/else。代码行更少,没有break 问题。

          这种嵌套是否会导致进一步的麻烦?

          一个问题是这样的开关嵌套很难阅读:在我注意到您使用嵌套开关之前,我不得不查看代码两次。这可能是一个维护问题,但这不是不使用嵌套开关的理由,只需谨慎地使用它,调整缩进以阐明发生了什么,并评论使用情况。 p>

          是否缺少休息;在一个案例不好的做法之后?

          忽略break 也可能导致维护/调试问题,但我不认为这是不好的做法。毕竟,它是 switch 语句的设计固有的。 fall through 评论总是受欢迎的,这样下一个人 - 或者你,几个月后重新访问你的代码 - 知道失败是故意的。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-04-10
            • 2010-10-30
            • 2016-05-13
            • 2016-02-21
            • 1970-01-01
            • 2012-08-11
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多