简体   繁体   English

我应该避免使用Java标签语句吗?

[英]Should I avoid using Java Label Statements?

Today I had a coworker suggest I refactor my code to use a label statement to control flow through 2 nested for loops I had created. 今天我有一个同事建议我重构我的代码,使用label语句来控制我创建的2个嵌套for循环的流量。 I've never used them before because personally I think they decrease the readability of a program. 我以前从未使用它们,因为我个人认为它们会降低程序的可读性。 I am willing to change my mind about using them if the argument is solid enough however. 如果论证足够坚实,我愿意改变主意使用它们。 What are people's opinions on label statements? 人们对标签声明的看法是什么?

Many algorithms are expressed more easily if you can jump across two loops (or a loop containing a switch statement). 如果您可以跳过两个循环(或包含switch语句的循环),则可以更轻松地表达许多算法。 Don't feel bad about it. 不要为此感到难过。 On the other hand, it may indicate an overly complex solution. 另一方面,它可能表明过于复杂的解决方案。 So stand back and look at the problem. 所以退后一步看看问题。

Some people prefer a "single entry, single exit" approach to all loops. 有些人更喜欢所有循环的“单入口,单出口”方法。 That is to say avoiding break (and continue) and early return for loops altogether. 也就是说完全避免中断(并继续)和早期返回循环。 This may result in some duplicate code. 这可能会导致一些重复的代码。

What I would strongly avoid doing is introducing auxilary variables. 我强烈要避免做的是引入辅助变量。 Hiding control-flow within state adds to confusion. 隐藏在州内的控制流动增加了混乱。

Splitting labeled loops into two methods may well be difficult. 将标记的循环分成两种方法可能很困难。 Exceptions are probably too heavyweight. 例外情况可能太重了。 Try a single entry, single exit approach. 尝试单入口,单退出方法。

Labels are like goto's: Use them sparingly, and only when they make your code faster and more importantly, more understandable, 标签就像goto一样:谨慎使用它们,只有当它们使代码更快更重要的是,更容易理解,

eg, 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. 例如,如果你处于六级深度的大循环中并且遇到一个条件使得循环的其余部分无意义地完成,那么在条件语句中有6个额外的陷阱门以提前退出循环是没有意义的。

Labels (and goto's) aren't evil, it's just that sometimes people use them in bad ways. 标签(和goto的)不是邪恶的,只是有时候人们以不好的方式使用它们。 Most of the time we are actually trying to write our code so it is understandable for you and the next programmer who comes along. 大多数时候我们实际上都在尝试编写代码,因此对于您和下一个程序员来说这是可以理解的。 Making it uber-fast is a secondary concern (be wary of premature optimization). 快速超速是一个次要问题(警惕过早优化)。

When Labels (and goto's) are misused they make the code less readable, which causes grief for you and the next developer. 当Labels(和goto)被滥用时,它们会使代码的可读性降低,这会让您和下一位开发人员感到悲伤。 The compiler doesn't care. 编译器不关心。

There are few occasions when you need labels and they can be confusing because they are rarely used. 您很少需要标签,因为它们很少使用,所以很容易混淆。 However if you need to use one then use one. 但是,如果您需要使用一个,请使用一个。

BTW: this compiles and runs. BTW:这个编译并运行。

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

I'm curious to hear what your alternative to labels is. 我很想知道你对标签的替代品是什么。 I think this is pretty much going to boil down to the argument of "return as early as possible" vs. "use a variable to hold the return value, and only return at the end." 我认为这几乎可以归结为“尽早返回”与“使用变量保持返回值,最后只返回”的论点。

Labels are pretty standard when you have nested loops. 当您有嵌套循环时,标签是非常标准的。 The only way they really decrease readability is when another developer has never seen them before and doesn't understand what they mean. 他们真正降低可读性的唯一方法是,其他开发人员以前从未见过它们并且不理解它们的含义。

I think with the new for-each loop, the label can be really clear. 我认为通过新的for-each循环,标签可以非常清晰。

For example: 例如:

sentence: for(Sentence sentence: paragraph) {
  for(String word: sentence) {
    // do something
    if(isDone()) {
      continue sentence;
    }
  }
}

I think that looks really clear by having your label the same as your variable in the new for-each. 我认为通过让你的标签与新的for-each中的变量相同,我看起来非常清楚。 In fact, maybe Java should be evil and add implicit labels for-each variables heh 事实上,也许Java应该是邪恶的,并为每个变量添加隐式标签

I have use a Java labeled loop for an implementation of a Sieve method to find prime numbers (done for one of the project Euler math problems) which made it 10x faster compared to nested loops. 我使用Java标记的循环来实现Sieve方法来查找素数(为项目Euler数学问题之一完成),这使得它比嵌套循环快10倍。 Eg if(certain condition) go back to outer loop. 例如,如果(某些条件)返回外循环。

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

I asked a C++ programmer how bad labeled loops are, he said he would use them sparingly, but they can occasionally come in handy. 我问过C ++程序员标签循环有多糟糕,他说他会谨慎使用它们,但它们偶尔会派上用场。 For example, if you have 3 nested loops and for certain conditions you want to go back to the outermost loop. 例如,如果您有3个嵌套循环,并且对于某些条件,您希望返回到最外层循环。

So they have their uses, it depends on the problem you were trying to solve. 所以他们有自己的用途,这取决于你试图解决的问题。

I've never seen labels used "in the wild" in Java code. 我从来没有在Java代码中看到过“野外”使用过的标签。 If you really want to break across nested loops, see if you can refactor your method so that an early return statement does what you want. 如果你真的想要突破嵌套循环,看看你是否可以重构你的方法,以便早期的return语句能够达到你想要的效果。

Technically, I guess there's not much difference between an early return and a label. 从技术上讲,我猜早期退货和标签之间没有太大区别。 Practically, though, almost every Java developer has seen an early return and knows what it does. 但实际上,几乎每个Java开发人员都看到了早期的回报,并知道它的作用。 I'd guess many developers would at least be surprised by a label, and probably be confused. 我猜许多开发人员至少会对标签感到惊讶,可能会感到困惑。

I was taught the single entry / single exit orthodoxy in school, but I've since come to appreciate early return statements and breaking out of loops as a way to simplify code and make it clearer. 我在学校教过单入/单出正统,但我已经开始欣赏早期的返回语句和断开循环,以简化代码并使其更清晰。

I'd argue in favour of them in some locations, I found them particularly useful in this example: 我在某些地方支持它们,我发现它们在这个例子中特别有用:


nextItem: for(CartItem item : user.getCart()) {

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

  }
  purchasedItems.add(item);
}

I never use labels in my code. 我从不在代码中使用标签。 I prefer to create a guard and initialize it to null or other unusual value. 我更喜欢创建一个后卫并将其初始化为null或其他异常值。 This guard is often a result object. 这个守卫通常是一个结果对象。 I haven't seen any of my coworkers using labels, nor found any in our repository. 我没有看到我的同事使用标签,也没有在我们的存储库中找到任何标签。 It really depends on your style of coding. 这真的取决于你的编码风格。 In my opinion using labels would decrease the readability as it's not a common construct and usually it's not used in Java. 在我看来,使用标签会降低可读性,因为它不是一个常见的结构,通常它不会在Java中使用。

Yes, you should avoid using label unless there's a specific reason to use them (the example of it simplifying implementation of an algorithm is pertinent). 是的,你应该避免使用标签,除非有特定的理由使用它们(简化算法实现的例子是相关的)。 In such a case I would advise adding sufficient comments or other documentation to explain the reasoning behind it so that someone doesn't come along later and mangle it out of some notion of "improving the code" or "getting rid of code smell" or some other potentially BS excuse. 在这种情况下,我建议添加足够的评论或其他文档来解释其背后的推理,以便有人不会在以后出现并将其从“改进代码”或“摆脱代码味道”的概念中删除或其他一些潜在的BS借口。

I would equate this sort of question with deciding when one should or shouldn't use the ternary if. 我会把这类问题等同于决定何时应该或不应该使用三元组。 The chief rationale being that it can impede readability and unless the programmer is very careful to name things in a reasonable way then use of conventions such as labels might make things a lot worse. 主要理由是它可能妨碍可读性,除非程序员非常小心地以合理的方式命名,否则使用标签之类的约定可能会使事情变得更糟。 Suppose the example using 'nextCondition' and 'nextItem' had used 'loop1' and 'loop2' for his label names. 假设使用'nextCondition'和'nextItem'的示例使用'loop1'和'loop2'作为他的标签名称。

Personally labels are one of those features that don't make a lot of sense to me, outside of Assembly or BASIC and other similarly limited languages. 个人标签是除了Assembly或BASIC以及其他类似限制语言之外对我来说没有多大意义的功能之一。 Java has plenty of more conventional/regular loop and control constructs. Java有许多传统/常规循环和控制结构。

I found labels to be sometimes useful in tests, to separate the usual setup, excercise and verify phases and group related statements. 我发现标签有时在测试中有用,可以分离常用的设置,练习和验证阶段以及组相关的语句。 For example, using the BDD terminology: 例如,使用BDD术语:

@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();
}

Your formatting choices may vary but the core idea is that labels, in this case, provide a noticeable distinction between the logical sections comprising your test, better than comments can. 您的格式选择可能会有所不同,但核心思想是,在这种情况下,标签会在构成测试的逻辑部分之间提供明显的区别,而不是评论。 I think the Spock library just builds on this very feature to declare its test phases. 我认为Spock库只是建立在这个功能的基础上来宣布它的测试阶段。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM