关于循环:是否应该避免使用Java标签语句?

关于循环:是否应该避免使用Java标签语句?

Should I avoid using Java Label Statements?

今天,我有一个同事建议我重构代码,以使用label语句控制通过我创建的2个嵌套的for循环的流。 我以前从未使用过它们,因为我个人认为它们会降低程序的可读性。 如果论点足够扎实,我愿意改变使用它们的想法。 人们对标签陈述有何看法?


如果您可以跳过两个循环(或包含switch语句的循环),则许多算法的表达会更容易。不要为此感到难过。另一方面,它可能表明解决方案过于复杂。因此,退后一步,看看问题所在。

有些人喜欢在所有循环中使用"单入口单出口"方法。也就是说,完全避免了中断(并继续)和尽早返回循环。这可能会导致某些重复的代码。

我强烈避免做的是引入辅助变量。将控制流隐藏在状态内会增加混乱。

将标记的循环分为两种方法可能很困难。异常可能太重了。尝试一次进入,一次退出方法。


标签就像goto的标签:谨慎使用标签,只有在它们使您的代码更快,更重要,更易于理解时,

e.g., If you are in big loops six levels deep and you encounter a condition that makes the rest of the loop pointless to complete, there's no sense in having 6 extra trap doors in your condition statements to exit out the loop early.

标签(和goto的标签)不是邪恶的,只是有时人们以不良的方式使用它们。大多数情况下,我们实际上是在尝试编写代码,因此您和随之而来的下一个程序员都可以理解。使其超快是次要问题(请提防过早的优化)。

如果滥用了Labels(和goto的标签),它们会使代码的可读性降低,从而给您和下一个开发人员带来麻烦。编译器不在乎。


在极少数情况下,您需要标签,由于它们很少使用,因此可能会造成混淆。但是,如果您需要使用一个,请使用一个。

顺便说一句:编译并运行。

1
2
3
4
5
6
class MyFirstJavaProg {  
        public static void main(String args[]) {
           http://www.javacoffeebreak.com/java101/java101.html
           System.out.println("Hello World!");
        }
}

我很好奇,您可以替代标签吗?我认为这几乎可以归结为"尽早返回"与"使用变量保存返回值,并且仅在最后返回"的论点。

当您有嵌套循环时,标签是非常标准的。它们真正降低可读性的唯一方法是,另一个开发人员以前从未见过它们,并且不了解它们的含义。


我使用Java标记的循环来实现Sieve方法的方法来查找素数(针对项目Euler数学问题之一),这使其比嵌套循环快10倍。例如,如果(某些条件)返回外循环。

1
2
3
4
5
6
7
8
9
10
11
12
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个嵌套循环,并且对于某些条件,则要返回最外层循环。

因此它们有其用途,这取决于您要解决的问题。


我在某些地方赞成使用它们,在此示例中我发现它们特别有用:

1
2
3
4
5
6
7
8
9
10
11
nextItem: for(CartItem item : user.getCart()) {

  nextCondition : for(PurchaseCondition cond : item.getConditions()) {
     if(!cond.check())
        continue nextItem;
     else
        continue nextCondition;

  }
  purchasedItems.add(item);
}


我认为使用新的for-each循环,标签可以非常清晰。

例如:

1
2
3
4
5
6
7
8
sentence: for(Sentence sentence: paragraph) {
  for(String word: sentence) {
    // do something
    if(isDone()) {
      continue sentence;
    }
  }
}

我认为,通过在新的for-each中使标签与变量相同,可以很清楚地看出这一点。实际上,也许Java应该是邪恶的,并为每个变量添加隐式标签,呵呵


我从未见过Java代码中"野外使用"的标签。如果您真的想打破嵌套循环,请查看是否可以重构您的方法,以便早期return语句可以满足您的要求。

从技术上讲,我认为提早退货和贴标签之间没有太大区别。但是,实际上,几乎每个Java开发人员都已经看到了早期回报,并且知道它做了什么。我想许多开发人员至少会对标签感到惊讶,并且可能会感到困惑。

在学校里,我曾教过单一入口/单一出口正统,但是从那时起,我开始欣赏早期的return语句和打破循环,以此简化代码并使其更加清晰。


我从不在代码中使用标签。我更喜欢创建一个防护并将其初始化为null或其他异常值。该防护通常是结果对象。我还没有看到任何同事使用标签,也没有在我们的存储库中找到任何同事。这实际上取决于您的编码风格。在我看来,使用标签会降低可读性,因为它不是常见的构造,并且通常不在Java中使用。


是的,除非有特殊原因,否则应避免使用标签(有关简化算法实现的示例是相关的)。在这种情况下,我建议添加足够的注释或其他文档来解释其背后的原因,以便以后不再有人提出来,并出于"改善代码"或"消除代码气味"的某种观念而使它混乱。其他潜在的BS借口。

我将把这种问题等同于确定何时应该使用或不应该使用三元组if。最主要的理由是它可能会妨碍可读性,除非程序员非常谨慎地以合理的方式命名事物,否则使用诸如标签之类的约定可能会使事情变得更糟。假设使用" nextCondition"和" nextItem"的示例将" loop1"和" loop2"用作其标签名称。

就组装或BASIC以及其他类似的受限语言而言,个人标签是那些对我而言没有太多意义的功能之一。 Java具有许多更常规/常规的循环和控制构造。


我发现标签有时在测试中很有用,可以将通常的设置,锻炼和验证阶段以及与组相关的语句分开。例如,使用BDD术语:

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void should_Clear_Cached_Element() throws Exception {
    given: {
        elementStream = defaultStream();
        elementStream.readElement();
        Assume.assumeNotNull(elementStream.lastRead());
    }
    when:
        elementStream.clearLast();
    then:
        assertThat(elementStream.lastRead()).isEmpty();
}

您的格式选择可能会有所不同,但核心思想是在这种情况下,标签在构成测试的逻辑部分之间提供了明显的区别,胜于注释。我认为Spock库只是基于此功能来声明其测试阶段。


推荐阅读

    写5条linux命令语句?

    写5条linux命令语句?,工作,地址,系统,信息,目录,命令,管理,标准,功能,文件,li

    linux命令行远程控制?

    linux命令行远程控制?,系统,地址,服务,网络,电脑,软件,工具,实时,网站,命令,W

    linux命令怎么控制的?

    linux命令怎么控制的?,地址,工作,系统,标准,命令,电脑,基础,管理,灵活,网站,l

    linux控制台停止命令?

    linux控制台停止命令?,地址,工具,平台,网络,下来,电脑,状态,命令,程序,进程,L

    linux循环复制命令?

    linux循环复制命令?,系统,文件,命令,目录,地址,源文件,文件夹,目标,文件名,

    linux命令行写循环?

    linux命令行写循环?,工作,系统,地址,命令,情况,定期,基础,连续,信息,文件,Lin

    linux命令控制声卡?

    linux命令控制声卡?,软件,检测,设备,工作,声卡,官方网站,标准,电脑,情况,位

    linux作业控制命令?

    linux作业控制命令?,工作,系统,信息,地址,管理,命令,目录,大地,行业,术语,lin

    linux循环命令脚本?

    linux循环命令脚本?,代码,系统,增长,工具,官网,项目,流程,数据,数字,底部,lin

    linux跳出死循环命令?

    linux跳出死循环命令?,系统,地址,数字,代码,官方网站,网络,工作,工具,信息,

    linux循环语句命令?

    linux循环语句命令?,地方,增长,数字,语句,流程,名称,工具,代码,数据,条件,Lin

    linux退出控制台命令?

    linux退出控制台命令?,地址,工作,命令,图片,管理,系统,目录,信息,标准,控制

    dolinux循环命令?

    dolinux循环命令?,系统,工具,时间,信息,增长,代码,对比,数字,官网,定期,如何

    linux切换命令控制台?

    linux切换命令控制台?,工作,地址,系统,管理,命令,控制台,目录,信息,标准,代

    linux命令控制联网?

    linux命令控制联网?,网络,系统,地址,工具,命令,环境,密码,信息,情况,基础,使

    linux控制声音的命令?

    linux控制声音的命令?,系统,数字,数据,命令,暂停,代码,盘中,环境,首页,手机,l

    linux控制台基本命令?

    linux控制台基本命令?,系统,工作,地址,信息,命令,管理,目录,工具,基础,控制

    linux命令打出控制台?

    linux命令打出控制台?,地址,工作,系统,管理,命令,工具,目录,基础,网络,信息,l

    linux命令行串口控制?

    linux命令行串口控制?,系统,设备,代码,数据,平台,地址,信息,波特率,控制台,

    嵌入式linux命令语句?

    嵌入式linux命令语句?,系统,环境,基础,网络,软件,基础知识,服务,设备,管理,