4

为什么java允许在方法中使用带标签的break?这有什么特殊目的或用途吗?我认为它只能在循环和开关中使用。

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
}
4

7 回答 7

2

我不知道为什么,但是Java 语言规范 #14.15中指定了该行为:

打破没有标签

没有标签的 break 语句试图将控制转移到最里面的封闭式 switch、while、do 或 for 立即封闭方法或初始化程序的语句;此语句称为中断目标,然后立即正常完成。
如果直接封闭的方法、构造函数或初始化程序中没有 switch、while、do 或 for 语句包含 break 语句,则会发生编译时错误。

打破标签(强调我的)

带有标签 Identifier 的 break 语句尝试将控制转移到封闭的带有标签的语句(第 14.7 节),该语句具有与其标签相同的 Identifier;此语句称为中断目标,然后立即正常完成。在这种情况下,break 目标不必是 switch、while、do 或 for 语句

带标签的中断使您能够在整个块(可以是循环)之后重定向代码,这在嵌套循环的情况下很有用。然而,它与 C goto 语句不同

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

于 2012-05-16T11:54:20.207 回答
2

您可以使用它立即跳出嵌套循环

out: { 
         for( int row=0; row< max; row++ ) {
             for( int col=0; col< max; col++ )
                 if( row == limit) break out;
             j += 1;
         }
     }

使用break外部循环没有多大意义,你会breaking在哪里?要打破void 函数,您可以使用 return 作为adarshr指出。

于 2012-05-16T11:49:23.427 回答
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");
}

这忽略了“休息后”。

于 2012-05-16T12:25:03.813 回答
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();
}

显然,这是一个人为的例子,但更具可读性。我的建议是,如果你觉得需要使用标签,几乎永远,你应该重构代码。

于 2012-05-16T13:03:00.890 回答
0

因为return在循环之外有使用语句!

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

    // do something with count
}
于 2012-05-16T11:53:45.403 回答
0

您可以使用带标签的中断来摆脱嵌套循环,就像这里一样

于 2012-05-16T11:50:28.707 回答
0

我强烈反对使用带标签的 break 语句。它几乎和 GOTO 一样糟糕。一次休息;可以/有必要结束循环或切换等。但根据我的经验:需要这种带标签的中断是不良控制流设计的指标。

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

如果您的方法被称为“getDrink()”并且它返回一个“牛奶”对象,那就没问题了。但是如果你的方法被称为“getWater()”,它应该抛出一个异常而不是返回牛奶......

所以而不是:

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";
}

}

Fazit:与其将块嵌套到块或多个循环中,不如嵌套方法并使用适当的异常处理。这增强了可读性和可重用性。

于 2016-05-30T09:58:13.043 回答