Java方法中的标记式跳出语句

4

为什么Java允许在方法中使用标记的break语句?这有什么特殊目的或用途吗?我认为它只能在循环和switch语句中使用。

public void testMeth(int count){
   label:
   break label;
}

但以下代码会导致编译错误。
public void testMeth(int count){
    break; // This gives an Error : break cannot be used outside of a loop or a switch
}

1
在我看来,最好避免使用break作为goto语句,因为从长远来看,它们会带来更多的麻烦。我讨厌需要处理到处都是goto语句的代码。 - ChadNC
7个回答

2
我不知道为什么,但这种行为在Java语言规范#14.15中有所说明: 没有标签的break 一个没有标签的break语句试图将控制转移到最内层的switch、while、do或for语句,该语句是立即封闭方法或初始化程序的目标,然后立即正常完成。
如果在直接封闭方法、构造函数或初始化程序中没有switch、while、do或for语句包含break语句,则会发生编译时错误。 带标签的break(重点是我的)
带标签的break语句尝试将控制转移到具有与其标签相同标识符的封闭标记语句(§14.7);该语句是称为break目标,然后立即正常完成。 在这种情况下,break目标不必是switch、while、do或for语句。 使用带有标签的break语句可以在整个代码块(可为循环)后重定向代码,在嵌套循环的情况下非常有用。然而,这与C语言的goto语句不同:

与C和C++不同,Java编程语言没有goto语句;标识符语句标签与出现在标记语句内任何位置的break(§14.15)或continue(§14.16)语句一起使用。


2
您可以使用此方法立即跳出嵌套循环
out: { 
         for( int row=0; row< max; row++ ) {
             for( int col=0; col< max; col++ )
                 if( row == limit) break out;
             j += 1;
         }
     }

在循环之外使用break并没有太多意义,你要break出去到哪里呢?如果要从无返回值函数中跳出,你可以像adarshr所指出的那样使用return。


我认为这个问题是关于在循环外使用 break 的。 - assylias
@ChristopheD:是的,伙计。我知道这一点(正如我之前提到的)。但我的问题是为什么可以在方法内部使用它,而不需要在循环或switch语句中使用。 - ironwood
@assylias:是的,assylias,那就是我的问题。 - ironwood

0

我强烈反对使用带标签的break语句。它几乎和GOTO一样糟糕。单个break;用于结束循环或switch等是可以接受/必要的。但根据我的经验:需要使用这种标签式break语句是控制流设计不良的指标。

在大多数情况下,恰当放置异常更有意义。但前提是,“跳转条件”可以被视为错误。如果您正确标记了方法,就可以影响什么可以被视为错误。

如果您的方法名为“getDrink()”,并且它返回一个“milk”对象,那是可以接受的。但如果您的方法名为“getWater()”,则应该抛出异常而不是返回milk...

因此,与其:

public class TestBad {

public static void main(String[] args) {
    String[] guys = {"hans", "john"};

    myLabel: {
        for(String guy: guys) {
            String drink = getDrink(guy);

            if(drink.equals("milk")) {
                // Handle "milk"??
                break myLabel;
            }

            // Do something with "non-milk"
        }
    }

    // Success? Non Success??
}

private static String getDrink(String guy) {
    if(guy.equals("hans"))
        return "milk";
    else
        return "water";
}

}

你应该使用:

public class TestGood {

public static void main(String[] args) {
    String[] guys = {"hans", "john"};

    try {
        handleStuff(guys);
    } catch (Exception e) {
        // Handle Milk here!
    }
}

private static void handleStuff(String[] guys) throws Exception {
    for(String guy: guys) {

        String drink = getWater(guy);

        // Do something with "water"
    }
}

private static String getWater(String guy) throws Exception {
    if(guy.equals("hans"))
        // The method may NEVER return anything else than water, because of its name! So:
        throw new Exception("No Water there!");
    else
        return "water";
}

}

结论:与其将块嵌套到块中或使用多个循环,我们应该嵌套方法并使用适当的异常处理。这样可以提高可读性和重用性。

0

您可以使用带标签的跳出语句来退出嵌套循环,就像这里


0

因为有return语句可用于循环外部!

public void testMeth(int count){
    if(count < 0) {
        return;
    }

    // do something with count
}

0

我自己发现了一个疯狂的用法。

public void testMeth(int count){
    label: if (true) {
          System.out.println("Before break");
          if (count == 2) break label;
          System.out.println("After break");
    }
    System.out.println("After IF");
}

或者

public void testMeth(int count){

    namedBlock: {
        System.out.println("Before break");
        if (count == 0) break namedBlock;
        System.out.println("After break");
    }

    System.out.println("After Block");
}

这将忽略“break之后”的内容。


0

这是另一个标签在循环之外有用的示例:

boolean cond1 = ...
if (cond1) {
    boolean cond1 = ...
    if (cond2) {
        boolean cond3 = ...
        if (cond3) {
            bar();
        } else {
            baz();
        }
    } else {
        baz();
    }
} else {
    baz();
}

...变成...

label: {
    boolean cond1 = ...
    if (cond1) {
        boolean cond1 = ...
        if (cond2) {
            boolean cond3 = ...
            if (cond3) {
                bar();
                break label;
            }
        }
    }
    baz();
}

一个人为的例子,显然更易读。我的建议是,如果你觉得需要使用标签,那么你应该重构代码。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接