1. 引言:为什么需要循环控制?
循环是编程语言中控制程序流程的核心结构之一,它允许我们重复执行特定的代码块,直到满足某个条件为止。在 Kotlin 中,循环控制不仅提供了传统的 for、while、do-while 循环,还引入了许多函数式编程风格的扩展函数,如 forEach、map、filter 等,使得循环操作更加简洁、安全且富有表达力。
本文将深入探讨 Kotlin 中各种循环控制结构的语法、特性、使用场景,并通过丰富的代码实例帮助您掌握如何在实际开发中高效地使用它们。
2. 传统循环结构
2.1 for 循环
Kotlin 的 for 循环用于遍历任何提供了迭代器(iterator)的对象,如范围、数组、集合等。
// 示例 1:遍历范围
fun main() {
// 遍历 1 到 5
for (i in 1..5) {
print("$i ") // 输出: 1 2 3 4 5
}
println()
// 遍历 5 到 1(递减)
for (i in 5 downTo 1) {
print("$i ") // 输出: 5 4 3 2 1
}
println()
// 指定步长
for (i in 1..10 step 2) {
print("$i ") // 输出: 1 3 5 7 9
}
println()
// 遍历数组
val fruits = arrayOf("Apple", "Banana", "Orange")
for (fruit in fruits) {
print("$fruit ") // 输出: Apple Banana Orange
}
println()
// 使用索引遍历数组
for (index in fruits.indices) {
println("索引 $index 对应的水果是 ${fruits[index]}")
}
// 输出:
// 索引 0 对应的水果是 Apple
// 索引 1 对应的水果是 Banana
// 索引 2 对应的水果是 Orange
// 同时获取索引和值
for ((index, value) in fruits.withIndex()) {
println("索引 $index 的值是 $value")
}
}
2.2 while 循环
while 循环先判断条件,条件为真时执行循环体。
// 示例 2:while 循环
fun main() {
var count = 5
while (count > 0) {
println("倒计时: $count")
count--
}
// 输出:
// 倒计时: 5
// 倒计时: 4
// 倒计时: 3
// 倒计时: 2
// 倒计时: 1
// 读取用户输入直到输入 "quit"
var input: String
do {
print("请输入命令 (输入 'quit' 退出): ")
input = readLine() ?: ""
println("你输入了: $input")
} while (input != "quit")
}
2.3 do-while 循环
do-while 循环先执行一次循环体,再判断条件,保证循环体至少执行一次。
// 示例 3:do-while 循环
fun main() {
var number: Int
do {
print("请输入一个正数: ")
number = readLine()?.toIntOrNull() ?: 0
} while (number <= 0)
println("你输入的正数是: $number")
// 模拟菜单选择
var choice: Int
do {
println("\n=== 菜单 ===")
println("1. 查看信息")
println("2. 修改设置")
println("3. 退出")
print("请选择 (1-3): ")
choice = readLine()?.toIntOrNull() ?: 0
when (choice) {
1 -> println("查看信息...")
2 -> println("修改设置...")
3 -> println("退出程序")
else -> println("无效选择,请重新输入")
}
} while (choice != 3)
}
3. 循环控制语句
3.1 break:跳出循环
break 用于完全终止循环的执行。
// 示例 4:break 语句
fun main() {
// 在数组中查找特定元素
val numbers = listOf(10, 20, 30, 40, 50, 60, 70)
val target = 40
var foundIndex = -1
for ((index, value) in numbers.withIndex()) {
if (value == target) {
foundIndex = index
break // 找到后立即跳出循环
}
}
if (foundIndex != -1) {
println("找到 $target 在索引 $foundIndex")
} else {
println("未找到 $target")
}
// 嵌套循环中的 break
outer@ for (i in 1..3) {
inner@ for (j in 1..3) {
if (i == 2 && j == 2) {
break@outer // 跳出外层循环
}
println("i=$i, j=$j")
}
}
// 输出:
// i=1, j=1
// i=1, j=2
// i=1, j=3
// i=2, j=1
}
3.2 continue:跳过本次迭代
continue 跳过当前循环的剩余语句,直接进入下一次迭代。
// 示例 5:continue 语句
fun main() {
// 打印 1-10 中的奇数
for (i in 1..10) {
if (i % 2 == 0) {
continue // 跳过偶数
}
print("$i ") // 输出: 1 3 5 7 9
}
println()
// 处理列表,跳过无效数据
val data = listOf("apple", "", "banana", null, "cherry", " ")
for (item in data) {
if (item.isNullOrBlank()) {
continue // 跳过空或空白字符串
}
println("处理: ${item.trim()}")
}
// 输出:
// 处理: apple
// 处理: banana
// 处理: cherry
// 嵌套循环中的 continue
outer@ for (i in 1..3) {
for (j in 1..3) {
if (j == 2) {
continue@outer // 跳过外层循环的当前迭代
}
println("i=$i, j=$j")
}
}
// 输出:
// i=1, j=1
// i=2, j=1
// i=3, j=1
}
3.3 return:从函数返回
在循环中使用 return 会直接结束整个函数。
// 示例 6:在循环中使用 return
fun findFirstEven(numbers: List<Int>): Int? {
for (num in numbers) {
if (num % 2 == 0) {
return num // 找到第一个偶数后立即返回
}
}
return null // 没有找到偶数
}
fun main() {
val numbers = listOf(1, 3, 5, 7, 8, 9, 10)
val result = findFirstEven(numbers)
println("第一个偶数是: $result") // 输出: 第一个偶数是: 8
// 使用 run 函数和标签 return
val firstOdd = run {
for (num in numbers) {
if (num % 2 != 0) {
return@run num // 从 run 函数返回
}
}
null
}
println("第一个奇数是: $firstOdd") // 输出: 第一个奇数是: 1
}
4. 函数式循环操作
4.1 forEach:遍历集合
forEach 是集合的扩展函数,提供了一种更函数式的遍历方式。
// 示例 7:forEach 的使用
fun main() {
val list = listOf("Kotlin", "Java", "Python", "JavaScript")
// 基本用法
list.forEach { language ->
println("语言: $language")
}
// 使用 it 简化
list.forEach { println("语言: $it") }
// 带索引的 forEach
list.forEachIndexed { index, language ->
println("索引 $index: $language")
}
// 在 map 上使用 forEach
val map = mapOf("a" to 1, "b" to 2, "c" to 3)
map.forEach { (key, value) ->
println("键: $key, 值: $value")
}
// 注意:forEach 中不能使用 break 或 continue
// 但可以使用 return 来模拟 break
list.forEach {
if (it == "Python") {
return@forEach // 相当于 continue
}
println("处理: $it")
}
// 输出:
// 处理: Kotlin
// 处理: Java
// 处理: JavaScript
}
4.2 其他函数式操作
Kotlin 标准库提供了丰富的函数式操作,可以替代传统的循环。
// 示例 8:函数式操作替代循环
fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// map:转换每个元素
val squares = numbers.map { it * it }
println("平方: $squares") // 输出: 平方: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
// filter:过滤元素
val evens = numbers.filter { it % 2 == 0 }
println("偶数: $evens") // 输出: 偶数: [2, 4, 6, 8, 10]
// reduce:累积操作
val sum = numbers.reduce { acc, num -> acc + num }
println("总和: $sum") // 输出: 总和: 55
// fold:带初始值的累积
val product = numbers.fold(1) { acc, num -> acc * num }
println("乘积: $product") // 输出: 乘积: 3628800
// takeWhile:取满足条件的元素直到条件不满足
val firstFew = numbers.takeWhile { it < 5 }
println("前几个: $firstFew") // 输出: 前几个: [1, 2, 3, 4]
// groupBy:分组
val grouped = numbers.groupBy { if (it % 2 == 0) "偶数" else "奇数" }
println("分组: $grouped") // 输出: 分组: {奇数=[1, 3, 5, 7, 9], 偶数=[2, 4, 6, 8, 10]}
// 链式调用
val result = numbers
.filter { it > 5 }
.map { it * 2 }
.take(3)
println("链式结果: $result") // 输出: 链式结果: [12, 14, 16]
}
5. 高级循环技巧
5.1 序列(Sequence)的惰性求值
序列提供了一种惰性求值的方式,可以优化大数据集的处理性能。
// 示例 9:序列的使用
fun main() {
val numbers = (1..1_000_000).toList()
// 普通集合操作(急切求值)
val start1 = System.currentTimeMillis()
val result1 = numbers
.filter { it % 2 == 0 }
.map { it * 2 }
.take(10)
val end1 = System.currentTimeMillis()
println("普通操作耗时: ${end1 - start1}ms") // 会处理整个列表
// 序列操作(惰性求值)
val start2 = System.currentTimeMillis()
val result2 = numbers.asSequence()
.filter { it % 2 == 0 }
.map { it * 2 }
.take(10)
.toList()
val end2 = System.currentTimeMillis()
println("序列操作耗时: ${end2 - start2}ms") // 只处理前10个元素
println("结果: $result1, $result2")
// 生成无限序列
val infiniteSequence = generateSequence(1) { it + 1 }
val first10 = infiniteSequence.take(10).toList()
println("无限序列前10个: $first10") // 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 斐波那契数列
val fibonacci = sequence {
var a = 0
var b = 1
yield(a)
yield(b)
while (true) {
val next = a + b
yield(next)
a = b
b = next
}
}
val first10Fibonacci = fibonacci.take(10).toList()
println("斐波那契前10项: $first10Fibonacci") // 输出: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
}
5.2 循环性能优化
了解不同循环方式的性能差异,选择最适合的方案。
// 示例 10:循环性能比较
fun main() {
val largeList = (1..1_000_000).toList()
// 方法1:传统 for 循环
var sum1 = 0L
var start = System.currentTimeMillis()
for (i in largeList.indices) {
sum1 += largeList[i]
}
var end = System.currentTimeMillis()
println("传统 for 循环耗时: ${end - start}ms, 结果: $sum1")
// 方法2:for-in 循环
var sum2 = 0L
start = System.currentTimeMillis()
for (num in largeList) {
sum2 += num
}
end = System.currentTimeMillis()
println("for-in 循环耗时: ${end - start}ms, 结果: $sum2")
// 方法3:forEach
var sum3 = 0L
start = System.currentTimeMillis()
largeList.forEach { sum3 += it }
end = System.currentTimeMillis()
println("forEach 耗时: ${end - start}ms, 结果: $sum3")
// 方法4:sum() 函数
start = System.currentTimeMillis()
val sum4 = largeList.sum()
end = System.currentTimeMillis()
println("sum() 函数耗时: ${end - start}ms, 结果: $sum4")
// 方法5:序列 + sum()
start = System.currentTimeMillis()
val sum5 = largeList.asSequence().sum()
end = System.currentTimeMillis()
println("序列 sum() 耗时: ${end - start}ms, 结果: $sum5")
}
6. 实战应用案例
6.1 文件处理
// 示例 11:文件读取与处理
import java.io.File
fun processFile(filePath: String) {
val file = File(filePath)
if (!file.exists()) {
println("文件不存在: $filePath")
return
}
// 逐行读取文件
println("=== 文件内容 ===")
file.forEachLine { line ->
println(line)
}
// 统计行数
val lineCount = file.useLines { lines ->
lines.count()
}
println("总行数: $lineCount")
// 查找包含特定关键词的行
val keyword = "Kotlin"
val matchingLines = mutableListOf<String>()
file.forEachLine { line ->
if (line.contains(keyword, ignoreCase = true)) {
matchingLines.add(line)
}
}
println("\n包含 '$keyword' 的行:")
matchingLines.forEachIndexed { index, line ->
println("${index + 1}. $lin
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/wuitanly/article/details/162857579



