首页 / Java 入门教程 / break、continue 与标签

Java 入门教程

break、continue 与标签

本教程共 100 篇 · 第 23 篇 · 更新于 2026-08-05 · 约 15 分钟阅读

JavaJava 入门教程breakcontinue标签

23. break、continue 与标签

本节目标:搞懂 break 怎么立刻跳出循环、continue 怎么跳过本轮,以及带标签的 break 如何在嵌套循环里精准跳出指定层。

循环跑着跑着,常有「到这儿不用再继续了」或「这轮不要了,直接下一轮」的需求。break 和 continue 就是干这个的。

没有它们会怎样

先感受一下缺了 break 的日子。在一堆数里找第一个能被 7 整除的数:

int[] nums = {3, 8, 14, 21, 35, 42};
int found = -1;
for (int i = 0; i < nums.length; i++) {
    if (nums[i] % 7 == 0 && found == -1) {   // 还得加个「没找到过」的判断
        found = nums[i];
    }
}
```java

数组有 6 个元素,第 3 个(14)就命中了,可循环还得老老实实把剩下 3 个走完。而且为了不被后面的 2135 覆盖掉结果,你被迫加了 `found == -1` 这个别扭的条件。

有了 break,逻辑立刻回归本意:

```java
int found = -1;
for (int num : nums) {
    if (num % 7 == 0) {
        found = num;
        break;              // 找到就走人,不多跑一步
    }
}

条件干净了,跑的圈数也少了。数组要是有一百万个元素,这个差别就不只是好看的问题。

break:立刻结束整个循环

break 一旦执行,循环直接终止,不管条件还成不成立。

public class BreakDemo {
    public static void main(String[] args) {
        for (int i = 1; i <= 10; i++) {
            if (i == 5) {
                break;          // 碰到 5 就停下
            }
            System.out.println(i);
        }
    }
}
```java

上面只打印 14,第 5 轮一进循环体就 break,整个 for 结束。常用来「找到了就走人」,比如在一堆数里找第一个偶数。

break 之后的代码永远执行不到,编译器会直接拦下来:

```java
for (int i = 0; i < 5; i++) {
    break;
    System.out.println(i);      // 永远到不了这
}
BreakDemo.java:5: error: unreachable statement
            System.out.println(i);
            ^
```bash

`unreachable statement` 意思是「这条语句没有任何路径能走到」。Java 把它当编译错误而不是警告,逼你把死代码删掉。

### break 只跳一层

这是个高频误解:break 结束的是**离它最近的那一层循环**,不是全部循环。

```java
for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 3; j++) {
        if (j == 2) {
            break;              // 只结束内层,外层照跑
        }
        System.out.println(i + "," + j);
    }
}

输出是 1,12,13,1 三行。内层每次被 break 掐断,但外层的 i 继续往下走。想一次跳出两层,得用后面讲的标签。

continue:跳过本轮,进下一轮

continue 不结束循环,只跳过当前这一轮剩下的代码,直接开始下一轮。

public class ContinueDemo {
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) {
            if (i == 3) {
                continue;       // 跳过 3,不打印
            }
            System.out.println(i);
        }
    }
}
```bash

打印 1245,第 3 轮被跳过了。适合「某些情况这轮不处理,但后面还要继续」的场景。

> [!NOTE]
> break 是「整个停」,continue 是「这轮停、后面还跑」。别记混:一个管全局退出,一个管本轮跳过。

### continuewhile 里的经典陷阱

for 里用 continue 很安全,因为步进段 `i++` 是循环结构的一部分,continue 之后照样会执行。但在 while 里,步进语句通常写在循环体最后一行,continue 会把它一起跳过:

```java
int i = 0;
while (i < 5) {
    if (i == 2) {
        continue;           // 跳过后面所有代码,包括下面的 i++
    }
    System.out.println(i);
    i++;                    // i == 2 时永远执行不到
}

i 卡在 2 上,条件 2 < 5 永远成立,程序死在这里。控制台什么都不再输出,CPU 一个核被吃满。

改法是把步进提到 continue 之前:

int i = 0;
while (i < 5) {
    int cur = i;
    i++;                    // 先前进,保证每轮都会动
    if (cur == 2) {
        continue;
    }
    System.out.println(cur);
}
```java

更省事的做法是换成 for,让步进段脱离循环体:

```java
for (int k = 0; k < 5; k++) {
    if (k == 2) {
        continue;           // for 的 k++ 照常执行,不会卡住
    }
    System.out.println(k);
}
Warning

循环体里出现 continue 时,先确认「改变条件的那句」在不在 continue 后面。在的话就是个定时炸弹。这条规则记住能省掉半夜排查死循环的功夫。

两者速查对照

对比项breakcontinue
作用终止整个循环结束本轮,进入下一轮
影响范围最近一层循环(或 switch)最近一层循环
后面的循环还跑吗不跑了继续跑
能用在 switch 里吗能,用来防穿透不能,只能用在循环里
能带标签吗
典型场景找到目标就退出、条件触发就中止过滤掉不需要处理的元素

用错地方编译器会拦:

Demo.java:6: error: continue outside of loop
        continue;
        ^
```text

```text
Demo.java:9: error: break outside switch or loop
        break;
        ^

看到这两条,检查是不是把语句写到了循环或 switch 的花括号外面,或者写进了 lambda 表达式里面(lambda 内部不能 break 外层循环)。

switch 里的 break 不是一回事

break 在 switch 里也能用,但语义不同:它是用来防止「穿透」到下一个 case,跟循环没关系。

// 老写法:每个 case 都要手动补 break,漏一个就穿透
int day = 2;
switch (day) {
    case 1:
        System.out.println("周一");
        break;
    case 2:
        System.out.println("周二");
        break;               // 漏掉这行,会继续打印「其他」
    default:
        System.out.println("其他");
}
```bash

漏写 break 是老 switch 的经典事故。Java 14 起正式支持箭头写法,从语法上根除了这个坑:

```java
// Java 14+ 推荐:箭头写法不穿透,不需要 break
int day = 2;
switch (day) {
    case 1 -> System.out.println("周一");
    case 2 -> System.out.println("周二");
    default -> System.out.println("其他");
}

新代码优先用箭头写法。传统的冒号写法依然合法(读老项目会遇到),但不建议在新代码里用。switch 的完整用法在第 20 章已经展开过。

Note

循环里套了 switch 时要格外小心:switch 里的 break 只会跳出 switch,不会跳出外面的循环。想在 switch 里直接结束循环,得给循环贴标签,然后写 break 标签名

标签:在嵌套循环里精准跳出

嵌套循环时,普通的 break 只能跳出最内层。想直接从外层跳出,得给外层循环贴个标签。

public class LabelDemo {
    public static void main(String[] args) {
        outer:                         // 标签名加冒号
        for (int i = 1; i <= 3; i++) {
            for (int j = 1; j <= 3; j++) {
                if (i == 2 && j == 2) {
                    break outer;       // 跳到 outer 标签之外
                }
                System.out.println(i + "," + j);
            }
        }
    }
}
```text

`break outer;` 直接结束贴了 `outer:` 标签的那层循环,而不是只结束内层。标签名随便起,但习惯上用小写。

输出是这四行:

```text
1,1
1,2
1,3
2,1

走到 i=2、j=2 时命中条件,两层循环同时终止,后面的 2,33,1 全都不会出现。对比一下:如果只写普通的 break3,1 这些还会照常打印。

标签名写错,编译器直接报错:

LabelDemo.java:8: error: undefined label: outter
                    break outter;
                    ^
```bash

`undefined label` 说明这个名字没定义过。检查标签声明处的拼写,以及标签是不是贴在了要跳出的那层循环上——标签必须写在循环语句的正前方,中间不能隔别的语句。

## continue 也能带标签

continue 同样能带标签,作用是跳到标签所在循环的下一次迭代:

```java
public class ContinueLabelDemo {
    public static void main(String[] args) {
        outer:
        for (int i = 1; i <= 3; i++) {
            for (int j = 1; j <= 3; j++) {
                if (j == 2) {
                    continue outer;    // 直接开始外层的下一轮
                }
                System.out.println(i + "," + j);
            }
        }
    }
}

输出只有 1,12,13,1。每次 j 走到 2,就放弃内层剩下的迭代,回到外层让 i 加 1 后重新开始。

把它和不带标签的 continue 对比:不带标签时,continue 只跳过内层的这一轮,内层还会继续跑 j=3;带上 outer 后,整个内层循环被放弃。

该不该用标签

标签能解决问题,但也是把双刃剑。

Warning

标签不是越多越好。滥用标签跳转会让代码像「goto」一样难读。多数情况靠方法抽取或加标志变量就能避开,标签只在没有更干净写法时才用。

两种常见的替代方案:

方案一:把嵌套循环抽成方法,用 return 退出。

public static int[] findPair(int[][] matrix, int target) {
    for (int i = 0; i < matrix.length; i++) {
        for (int j = 0; j < matrix[i].length; j++) {
            if (matrix[i][j] == target) {
                return new int[]{i, j};   // return 天然跳出所有层
            }
        }
    }
    return null;                          // 没找到
}
```java

`return` 比 `break outer` 更直白:这个方法的任务完成了,走人。顺带还把「查找」这件事变成了一个有名字、能复用、能单独测试的方法。

**方案二:用标志变量控制外层条件。**

```java
boolean found = false;
for (int i = 0; i < 3 && !found; i++) {
    for (int j = 0; j < 3; j++) {
        if (i == 2 && j == 2) {
            found = true;
            break;                        // 只跳内层
        }
    }
}

外层条件加上 && !found,内层置位后外层自然停。缺点是多了个变量、条件变长,两层还行,三层就绕了。

一条实用的取舍:两层嵌套优先抽方法用 return,三层以上且抽不出方法时才考虑标签。 真用了标签,标签名要起得有意义,outersearchLoop 都比 al1 强。

Tip

面试常问 break 和 continue 区别。一句话:break 终止循环,continue 跳过当轮。带标签的版本只是把作用范围从「最近一层」扩大到「指定那层」。

常见疑问

问:标签只能贴在循环上吗?

不是。Java 允许给任意语句块贴标签,然后用 break 标签名 从块中跳出:

block: {
    if (x < 0) {
        break block;        // 直接跳到块结束
    }
    System.out.println("x 非负");
}
```java

不过这种用法极少见,可读性也一般。`continue` 就不同了,它只能配循环用,贴在普通块上的标签不能被 continue 引用。

**问:`break` 能跳出 if 吗?**

不能。if 不是循环,`break` 在 if 里指的是包着这个 if 的循环或 switch。如果 if 外面既没循环也没 switch,就会报 `break outside switch or loop`。想提前结束一段 if 逻辑,用 return 或者把条件反过来写。

**问:一个循环里能写多个 break 吗?**

能,语法上没限制。但两三个 break 散在不同分支里,读代码的人得把整个循环体扫一遍才敢确定退出时机。这时候通常意味着这段逻辑该拆成方法了——拆完每个出口变成一个 return,意图反而更清楚。