今天我有一位同事建议我重构我的代码,使用label语句来控制我创建的2个嵌套for循环的流量。我以前从未使用它们,因为我个人认为它们会降低程序的可读性。如果论证足够坚实,我愿意改变主意使用它们。人们对标签声明的看法是什么?
答案 0 :(得分:49)
如果你可以跳过两个循环(或包含switch语句的循环),很容易表达很多算法。不要为此感到难过。另一方面,它可能表明过于复杂的解决方案。所以请退一步看看问题。
有些人更喜欢所有循环的“单入口,单出口”方法。也就是说完全避免中断(并继续)和早期返回循环。这可能会导致一些重复的代码。
我强烈要避免做的是引入辅助变量。隐藏在州内的控制流动会增加混乱。
将标记的循环拆分成两种方法可能很困难。例外情况可能太重了。尝试单一条目,单一退出方式。
答案 1 :(得分:33)
标签就像goto一样:谨慎使用它们,只有当它们使你的代码更快时才会更强和更重要的是,更容易理解,
例如,如果你处于六级深度的大循环中并且遇到一个条件使得循环的其余部分无意义地完成,那么在条件语句中有6个额外的陷阱门以提前退出循环是没有意义的。
标签(和goto的)并不是邪恶的,只是有时候人们以不好的方式使用它们。大多数时候我们实际上都在尝试编写代码,因此对于您和下一个程序员来说这是可以理解的。快速超速是一个次要问题(对过早优化保持警惕)。
当Labels(和goto)被滥用时,它们会使代码的可读性降低,这会让您和下一位开发人员感到悲伤。编译器无关紧要。
答案 2 :(得分:27)
很少有人需要标签,因为它们很少使用而会引起混淆。但是,如果您需要使用一个,请使用一个。
BTW:这会编译并运行。
class MyFirstJavaProg {
public static void main(String args[]) {
http://www.javacoffeebreak.com/java101/java101.html
System.out.println("Hello World!");
}
}
答案 3 :(得分:8)
我很想知道你对标签的替代品是什么。我认为这几乎可以归结为“尽早返回”与“使用变量保存返回值,最后只返回”的论点。
当您使用嵌套循环时,标签非常标准。他们真正降低可读性的唯一方法是,另一位开发人员以前从未见过他们并且不明白他们的意思。
答案 4 :(得分:5)
我从未在Java代码中看到过“野外”使用的标签。如果你真的想要突破嵌套循环,看看你是否可以重构你的方法,以便早期的return语句能够达到你想要的效果。
从技术上讲,我猜早期退货和标签之间没有太大区别。但实际上,几乎每个Java开发人员都看到了早期的回报,并知道它的作用。我猜许多开发人员至少会对标签感到惊讶,可能会感到困惑。
我在学校教过单入/单出正统,但我已经开始欣赏早期的返回语句和断开循环,以简化代码并使其更清晰。
答案 5 :(得分:5)
我认为使用新的for-each循环,标签可以非常清晰。
例如:
sentence: for(Sentence sentence: paragraph) {
for(String word: sentence) {
// do something
if(isDone()) {
continue sentence;
}
}
}
我认为通过让您的标签与新的for-each中的变量相同,我看起来非常清楚。事实上,也许Java应该是邪恶的,并且为每个变量添加隐式标签
答案 6 :(得分:5)
我认为在某些地方支持它们,我发现它们在这个例子中特别有用:
nextItem: for(CartItem item : user.getCart()) {
nextCondition : for(PurchaseCondition cond : item.getConditions()) {
if(!cond.check())
continue nextItem;
else
continue nextCondition;
}
purchasedItems.add(item);
}
答案 7 :(得分:5)
我使用Java标记的循环来实现Sieve方法来查找素数(为项目Euler数学问题之一完成),这使得它比嵌套循环快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个嵌套循环,并且对于某些条件,您想要返回最外层循环。
所以他们有自己的用途,这取决于你试图解决的问题。
答案 8 :(得分:3)
我从不在代码中使用标签。我更喜欢创建一个保护并将其初始化为 null 或其他异常值。这个守卫通常是一个结果对象。我没有看到我的同事使用标签,也没有在我们的存储库中找到任何标签。这真的取决于你的编码风格。在我看来,使用标签会降低可读性,因为它不是一个常见的结构,通常它不会在Java中使用。
答案 9 :(得分:1)
是的,你应该避免使用标签,除非有特定的理由使用它们(简化算法实现的例子是相关的)。在这种情况下,我会建议添加足够的评论或其他文档来解释其背后的推理,以便某人以后不会出现并将其从“改进代码”的某些概念中删除。或者&#34;摆脱代码味道&#34;或其他一些潜在的BS借口。
我会把这类问题等同于决定何时应该或不应该使用三元if。主要理由是它可能会妨碍可读性,除非程序员非常小心地以合理的方式命名,否则使用标签之类的约定可能会使事情变得更糟。假设示例使用&#39; nextCondition&#39;和&#39; nextItem&#39;使用过&#39; loop1&#39;和&#39; loop2&#39;为他的标签名称。
在Assembly或BASIC以及其他类似限制语言之外,个人标签是对我来说没有多大意义的功能之一。 Java有很多传统/常规循环和控制结构。
答案 10 :(得分:0)
我发现标签有时在测试中有用,可以分离常用的设置,练习和验证阶段以及组相关的语句。例如,使用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();
}
您的格式选择可能会有所不同,但核心思想是,在这种情况下,标签会在构成测试的逻辑部分之间提供明显的区别,而不是评论。我认为Spock库正是建立在这个特性上,以宣告其测试阶段。