今天我的同事建议我重构我的代码,使用标签语句来控制我创建的2个嵌套for循环的流程。我从未使用过它们,因为我个人认为它们会降低程序的可读性。然而,如果有足够充分的理由,我愿意改变对它们的看法。那么,人们对标签语句有什么看法呢?
很多算法在跨越两个循环(或包含 switch 语句的循环)时会更容易表达。不要因此感到难过。但另一方面,这可能意味着一个过于复杂的解决方案。因此,请退后一步,看看问题本身。
有些人喜欢对所有循环采用“单入口,单出口”的方法。也就是说,完全避免使用 break(和 continue)以及提前退出循环。这可能会导致一些重复代码。
我强烈反对引入辅助变量。在状态中隐藏控制流程只会增加混乱。
将带标签的循环拆分为两个方法可能会很困难。异常可能太重了。请尝试使用单入口,单出口的方法。
标签有点像goto语句:要谨慎使用,仅当它们能使您的代码更快 并且 更重要的是,更易于理解时使用。
例如,如果您在六层深的大型循环中遇到一个条件,使得完成循环的其余部分变得无意义,那么在您的条件语句中添加6个额外的陷阱门以尽早退出循环就没有意义了。
标签(和goto语句)并不邪恶,只是有时人们会以错误的方式使用它们。大多数情况下,我们实际上是试图编写易于理解的代码,以便您和下一个程序员都能够理解。使其超级快速只是次要关注点(要谨慎避免过度优化)。
当标签(和goto语句)被误用时,它们会使代码变得不可读,这会给您和下一个开发人员带来困扰。编译器并不关心这些。
有时候需要使用标签,但它们很少被使用,因此可能会让人困惑。但如果您确实需要使用,则可以使用。
顺便说一下:这可以编译并运行。
class MyFirstJavaProg {
public static void main(String args[]) {
http://www.javacoffeebreak.com/java101/java101.html
System.out.println("Hello World!");
}
}
我很想听听您对标签的替代方案。我认为这基本上将归结为“尽早返回”与“使用变量保存返回值,并仅在最后返回”的争论。
当嵌套循环时,标签是相当标准的。它们真正降低可读性的唯一方式是另一个开发人员从未见过它们并且不理解它们的含义。
我曾经使用Java标记循环来实现素数筛法,以找到质数(为项目欧拉中的一道数学问题而完成),相比于嵌套循环,这使运行速度快了10倍。例如,如果(满足某个条件),则返回到外部循环。
private static void testByFactoring() {
primes: for (int ctr = 0; ctr < m_toFactor.length; ctr++) {
int toTest = m_toFactor[ctr];
for (int ctr2 = 0; ctr2 < m_divisors.length; ctr2++) {
// max (int) Math.sqrt(m_numberToTest) + 1 iterations
if (toTest != m_divisors[ctr2]
&& toTest % m_divisors[ctr2] == 0) {
continue primes;
}
} // end of the divisor loop
} // end of primes loop
} // method
我询问了一位C++程序员关于不良标记循环的问题,他说他会谨慎使用它们,但有时候它们可能会派上用场。例如,如果您有3个嵌套循环,并且对于某些条件,您希望返回到最外层循环。
因此,它们有其用途,这取决于您试图解决的问题。
在某些地方,我会支持使用它们。例如,在这个例子中,我发现它们特别有用:
nextItem: for(CartItem item : user.getCart()) {
nextCondition : for(PurchaseCondition cond : item.getConditions()) {
if(!cond.check())
continue nextItem;
else
continue nextCondition;
}
purchasedItems.add(item);
}
sentence: for(Sentence sentence: paragraph) {
for(String word: sentence) {
// do something
if(isDone()) {
continue sentence;
}
}
}
我认为通过将标签与新的for-each变量名称相同,可以使其更加清晰易懂。实际上,也许Java应该增加隐式标签用于for-each变量。
continue sentence;
并不会继续处理内部循环处理的单词所组成的句子,而是继续处理下一个句子/同一段落。 - greybeard我从不在代码中使用标签。我更喜欢创建一个守卫并将其初始化为null或其他异常值。这个守卫通常是一个结果对象。我没有看到我的同事使用标签,也没有在我们的代码库中找到任何标签。这真的取决于你编码的风格。在我看来,使用标签会降低可读性,因为它不是一个常见的结构,通常不用于Java。