1. 概述

本文深入探讨 Kotlin 中的结构化跳转表达式(structural jump expressions)。

简而言之,**Kotlin 提供了三种结构化跳转关键字:returnbreakcontinue**。接下来我们将结合是否使用标签(label)两种情况,详细解析它们的行为和实际应用场景。对于熟悉 Java 的开发者来说,这些关键字看似眼熟,但在 Kotlin 中结合 lambda 和标签的用法更为灵活,稍不注意就容易踩坑 ❌。

2. Kotlin 中的标签(Label)

在 Kotlin 中,几乎任何表达式都可以被打上标签。

标签的定义方式是:一个标识符后跟 @ 符号,例如 abc@loop@ 都是合法的标签。

要为某个表达式添加标签,只需将其放在表达式前面即可:

loop@ for (i in 1..10) {
    // some code 
}

这个特性在嵌套循环或函数式编程中尤为有用,能精准控制程序流跳转的目标。

3. break 语句

基本用法(无标签)

不带标签的 break 会终止最近一层的封闭循环

示例:

@Test
fun givenLoop_whenBreak_thenComplete() {
    var value = ""
    for (i in "hello_world") {
        if (i == '_') break
        value += i.toString()
    }
    assertEquals("hello", value)
}

当遇到 '_' 字符时,循环立即退出,最终 value"hello"

带标签的 break

使用标签时,break@label 会跳出对应标签所标记的外层循环

@Test
fun givenLoop_whenBreakWithLabel_thenComplete() {
    var value = ""
    outer_loop@ for (i in 'a'..'d') {
        for (j in 1..3) {
            value += "" + i + j
            if (i == 'b' && j == 1)
                break@outer_loop
        }
    }
    assertEquals("a1a2a3b1", value)
}

在这个例子中,当 i == 'b'j == 1 时,直接跳出 outer_loop@ 标记的外层循环,因此后续的 'c''d' 不再执行。

⚠️ 踩坑提醒:如果不加标签,break 只能跳出内层循环,这是新手常犯错误。

4. continue 语句

基本用法(无标签)

不带标签的 continue 跳过当前迭代,进入最近一层循环的下一次迭代

@Test
fun givenLoop_whenContinue_thenComplete() {
    var result = ""
    for (i in "hello_world") {
        if (i == '_') continue
        result += i
    }
    assertEquals("helloworld", result)
}

遇到 '_' 时跳过拼接操作,继续处理下一个字符。

带标签的 continue

使用标签时,continue@label 会跳转到指定标签对应的循环进行下一次迭代

@Test
fun givenLoop_whenContinueWithLabel_thenComplete() {
    var result = ""
    outer_loop@ for (i in 'a'..'c') {
        for (j in 1..3) {
            if (i == 'b') continue@outer_loop
            result += "" + i + j
        }
    }
    assertEquals("a1a2a3c1c2c3", result)
}

一旦 i == 'b',整个内层循环被跳过,直接进入外层循环的下一轮(即 i='c'),所以 'b1', 'b2', 'b3' 都不会被拼接到结果中。

📌 小技巧:这种写法在多层嵌套中比布尔标志位更清晰、更高效。

5. return 语句

默认行为(无标签)

无标签的 return 从最近的 命名函数或匿名函数返回

@Test
fun givenLambda_whenReturn_thenComplete() {
    var result = returnInLambda();
    assertEquals("hello", result)
}

private fun returnInLambda(): String {
    var result = ""
    "hello_world".forEach {
        if (it == '_') return result  // 直接从 returnInLambda 函数返回
        result += it.toString()
    }
    return result
}

⚠️ 注意:这里的 return 是从整个函数 returnInLambda() 返回,而不是仅退出 lambda。这也是为什么最后一行 return result 实际上无法到达(unreachable code)。

在匿名函数中使用 return

✅ 匿名函数支持局部 return,可用于模拟 continue 行为:

@Test
fun givenAnonymousFunction_return_thenComplete() {
    var result = ""
    "hello_world".forEach(fun(element) {
        if (element == '_') return  // 从匿名函数返回,相当于 continue
        result += element.toString()
    })
    assertEquals("helloworld", result)
}

因为 return 在匿名函数内部只退出该函数本身,不影响外部 forEach 的执行流程。

Lambda 中的 labeled return

Lambda 表达式本身不能直接使用无标签的 return(会报错),但可以通过 显式标签隐式标签 实现类似效果。

显式标签返回

@Test
fun givenLambda_whenReturnWithExplicitLabel_thenComplete() {
    var result = ""
    "hello_world".forEach lit@{
        if (it == '_') {
            return@lit  // 返回到 lambda 外部,继续下一次 forEach
        }
        result += it.toString()
    }
    assertEquals("helloworld", result)
}

隐式标签返回(推荐写法)

@Test
fun givenLambda_whenReturnWithImplicitLabel_thenComplete() {
    var result = ""
    "hello_world".forEach {
        if (it == '_') {
            return@forEach  // 使用函数名作为隐式标签
        }
        result += it.toString()
    }
    assertEquals("helloworld", result)
}

✅ 推荐使用 return@forEach 这种写法,语义清晰且无需额外定义标签。

使用 return 模拟 break 效果(跳出 lambda 外部代码块)

有时我们需要从 lambda 内部“跳出”到外层作用域,这就需要用到 带标签的代码块,比如 run {}with {} 等。

@Test
fun givenAnonymousFunction_returnToLabel_thenComplete() {
    var result = ""
    run loop@{
        "hello_world".forEach {
            if (it == '_') return@loop  // 跳出整个 run 块
            result += it.toString()
        }
        // 如果没有 break,这里会被执行
        result += "_finished"
    }
    assertEquals("hello", result)  // 注意:_finished 并未拼接
}

📌 场景说明:这相当于在 lambda 中实现了 break 的逻辑——提前终止外层代码块的执行。

6. 总结

本文系统梳理了 Kotlin 中 returnbreakcontinue 的使用方式,重点包括:

  • break / continue 支持标签,可精准控制嵌套循环跳转
  • return 在命名函数中默认返回整个函数
  • ✅ 匿名函数支持局部 return,适合实现 continue 类似逻辑
  • ✅ Lambda 必须使用 return@label 才能实现局部退出
  • ✅ 利用 run { } + labeled return 可实现从 lambda “跳出”外层逻辑,类似 break

这些特性在处理复杂逻辑(如状态机、嵌套遍历、事件过滤)时非常实用,但也容易误用。建议结合 IDE 提示和单元测试确保跳转逻辑符合预期。

完整示例代码可在 GitHub 获取:https://github.com/Baeldung/kotlin-tutorials/tree/master/core-kotlin-modules/core-kotlin-lang-2


原始标题:Kotlin return, break, continue Keywords