【问题标题】:Java Continue Label is Deprecated?Java 继续标签已弃用?
【发布时间】:2011-10-02 18:37:07
【问题描述】:

我有 2 个 fors,在嵌套 for 之后,如果嵌套 for 中的条件为真,我不想执行一些代码。如果我使用 break 代码将执行,所以(正如我在 SCJP 中学到的)我使用 continue label; 作为外部 for。 这是 Java 的弃用用法吗?老式的?有人建议使用递归或其他方法,但对我来说,这是完全正常、简单、最新且完美的方法。

here:
for (bla bla) {
   for (bla bla) {
      if (whatever) continue here;
   }
// some code I don't want to execute if whatever is true
}

谢谢

编辑:
如果我将我的问题改写为:如何在多个嵌套 fors 之间“导航”?这种方法将是“推荐”的方式吗?因为这是 SCJP Book 中所说的。如果不是......这是否意味着Katherine SierraBert Bates 是错误的?

编辑2:
为什么不鼓励continue label;?我想要一个关于 OOP 或 Java 的概念或内部工作原理的答案,可能会出什么问题..

【问题讨论】:

  • 如果您需要在多个嵌套 for 循环之间导航,那么这不仅是推荐的方式,而且是唯一的方式。所以他们是对的。虽然我建议避免在多个嵌套的 for 循环之间导航。

标签: java deprecated continue


【解决方案1】:

答案是:视情况而定。如果您发现自己经常使用continue,那么这可能表明您的代码需要重构。但是,在您给出的场景中,它似乎是一个可以使用它的地方。

【讨论】:

    【解决方案2】:

    我会重构以使其更具可读性。

    例子:

    if (!checkWhatever()) {
        // some code I don't want to execute if whatever is true
    }
    boolean checkWhatever() {
        for (bla bla) {
           for (bla bla) {
              if (whatever) return false;
           }
        }
        return true;
    }
    

    【讨论】:

    • 如果你有 5 个嵌套级别?对于特定情况,此解决方案可以。我想要一个概括。
    • @Cosmin Vacaroiu 5 嵌套循环?听起来像是设计问题,应该重构。
    • 没有通用的方法可以替换“继续标注”。另一方面,总有一些方法可以替代它。
    • 如果你有 Object[][][][][] 你会怎么做才不会是糟糕的设计?
    • @Cosmin,我想说,没有Object[][][][][][](除非你有一个5维物理问题。;)在某些时候使用一个类来包装@987654323是有意义的@ 或 [][].
    【解决方案3】:

    我会说它气馁。在替代方案更复杂或更容易出错(即不是改进)的情况下,它仍然具有有效用途

    【讨论】:

    • +1 即使我不认为不鼓励中断/继续使用标签。气味通常是嵌套循环,但并非总是如此。
    • @Kaj。不太同意。双嵌套循环,如果足够简单,闻起来并不多。对 LABELED continue 的需求增加了气味 - 考虑重构的时间 - 将内部循环移动到自己的方法。 Cosmin:如果代码和你的例子一样简单,那么是的,KISS。如果方法变得更复杂,打破内部细节,使外部结构一目了然。并消除对标记为 continue 的需要作为可读性的一部分。
    【解决方案4】:

    参考您的编辑 2,它总是看起来有点不确定,因为它违反了比 OO 更古老的编程正统:“结构化编程”(参见 http://en.wikipedia.org/wiki/Structured_programming)。它也带有 goto 的味道,所有优秀的程序员都知道,如果他们在代码中加入 goto,就需要承认。

    可能有人担心它可能会使编译器更难分析函数的控制流,但它是一种通常出于效率原因而使用的工具。例如,java.lang.String 的 Apache 实现在这个函数中使用它,至少是为了优化:

    /*
     * An implementation of a String.indexOf that is supposed to perform
     * substantially better than the default algorithm if the "needle" (the
     * subString being searched for) is a constant string.
     *
     * For example, a JIT, upon encountering a call to String.indexOf(String),
     * where the needle is a constant string, may compute the values cache, md2
     * and lastChar, and change the call to the following method.
     */
    @SuppressWarnings("unused")
    private static int indexOf(String haystackString, String needleString,
            int cache, int md2, char lastChar) {
        char[] haystack = haystackString.value;
        int haystackOffset = haystackString.offset;
        int haystackLength = haystackString.count;
        char[] needle = needleString.value;
        int needleOffset = needleString.offset;
        int needleLength = needleString.count;
        int needleLengthMinus1 = needleLength - 1;
        int haystackEnd = haystackOffset + haystackLength;
        outer_loop: for (int i = haystackOffset + needleLengthMinus1; i < haystackEnd;) {
            if (lastChar == haystack[i]) {
                for (int j = 0; j < needleLengthMinus1; ++j) {
                    if (needle[j + needleOffset] != haystack[i + j
                            - needleLengthMinus1]) {
                        int skip = 1;
                        if ((cache & (1 << haystack[i])) == 0) {
                            skip += j;
                        }
                        i += Math.max(md2, skip);
                        continue outer_loop;
                    }
                }
                return i - needleLengthMinus1 - haystackOffset;
            }
    
            if ((cache & (1 << haystack[i])) == 0) {
                i += needleLengthMinus1;
            }
            i++;
        }
        return -1;
    }
    

    【讨论】:

      【解决方案5】:

      通过将内部循环放在自己的方法中,重构使其更具可读性:

      for (bla bla) {   
        DoStuff();
      }
      void DoStuff() {
        for (bla bla) {
          if (whatever) return;
        }
        // some code to execute when whatever is false.
      }
      

      原则:如果方法变得复杂到需要对块进行标记,请考虑将该方法的一部分重构为单独的方法,这样就不需要标记。

      同样,将方法制作为三个深度的循环也是不明智的。除非循环非常简单。即使不需要标签。通过将复杂性隐藏在其他方法中,确保最外层的流结构(循环、if/else 或开关)易于阅读。即使这些方法只从一个地方调用。

      【讨论】:

      • @Mikael 有正确的想法;但是他的重构是不正确的——它没有保留原始的行为——“// some code”是内部循环的一部分,而不是外部循环。我提议将此更改作为对他帖子的编辑以及我的解释性段落,但由于更改/更改帖子的含义太大而被审稿人拒绝。所以我在这里发布一个单独的答案。
      【解决方案6】:

      使用一个名为“成功”的布尔值或类似的东西。 它更容易阅读和遵循流程。 Gotos 应该只用于错误处理。

      boolean success = true;
      for(int outer = 0; (outer <= outerLimit) && sucess; outer++)
      {
          for(int inner = 0; (inner <= innerLimit) && success; inner++)
          {
              if( !doInnerStuff() )
              {
                  success = false;
              }
          }
      
          if( success )
          {
              success = doOuterStuff();
          }
      }
      

      【讨论】:

      • 您可能想在success = false 之后添加break 或添加一个条件以确保退出内部循环。
      猜你喜欢
      • 2018-04-20
      • 1970-01-01
      • 2018-04-19
      • 2014-12-03
      • 1970-01-01
      • 2022-07-10
      • 1970-01-01
      • 1970-01-01
      • 2012-08-08
      相关资源
      最近更新 更多