一、迭代器(Iterator)的定义
在 Scala 中,迭代器(Iterator) 是一种用于遍历集合(如 List、Set、Map 等)元素的对象,它提供了一种按需访问集合元素的方式 ——不会一次性加载集合所有元素到内存,而是通过指针记录当前遍历位置,每次仅获取下一个元素,遍历完成后迭代器不可复用。
迭代器的核心特征:
- 是 “单向” 的:只能从前往后遍历,无法回退;
- 是 “惰性” 的:仅在调用
next()时才获取下一个元素; - 遍历后失效:迭代器遍历完所有元素后,再次调用
hasNext()会返回false,next()会抛出NoSuchElementException。
Scala 中获取迭代器的方式:集合.iterator(如List(1,2,3).iterator)。
二、迭代器的基本使用
迭代器的核心操作依赖两个方法:hasNext()(判断是否还有下一个元素)和next()(获取下一个元素),常见使用方式有 3 种:
1. 基础 while 循环(最底层用法)
scala
// 1. 创建迭代器
val it = List(1,2,3,4,5).iterator
// 2. 遍历:hasNext()判断是否有元素,next()获取元素
while (it.hasNext) {
println(it.next()) // 依次输出1、2、3、4、5
}
2. foreach 遍历(简洁写法)
迭代器支持foreach方法,底层仍基于hasNext()和next()实现:
scala
val it = List("a", "b", "c").iterator
it.foreach(ele => println(ele)) // 依次输出a、b、c
3. 模式匹配 / 解构遍历
结合 Scala 模式匹配简化元素提取:
scala
val it = List("a", "b", "c").iterator
it.foreach(ele => println(ele)) // 依次输出a、b、c
注意:迭代器不可复用
scala
val it = List(1,2).iterator
it.next() // 获取1
it.next() // 获取2
it.hasNext // false,迭代器已耗尽
it.next() // 抛出NoSuchElementException
scala
一、Scala 迭代器(Iterator)的定义
Scala 中的Iterator是一个单向、惰性的遍历工具,用于逐个访问集合(如 List、Set、Map 等)中的元素,它本身不存储数据,仅提供访问集合元素的接口。
- 迭代器有两个核心状态:
hasNext(判断是否还有下一个元素)和next(获取下一个元素并移动指针)。 - 特性:单向不可逆(一旦调用
next移动指针,无法回退)、惰性计算(仅在调用next时才获取元素,而非提前加载所有元素)。
语法定义:
scala
val iter: Iterator[T] = 集合.iterator // T为集合元素类型
二、Scala 迭代器的基本使用
迭代器的核心操作围绕hasNext和next展开,常见使用方式有 3 种:
1. 基础循环(while)
最原生的用法,通过hasNext判断、next获取元素:
scala
// 1. 创建迭代器
val list = List(1,2,3,4,5)
val iter = list.iterator
// 2. 遍历迭代器
while (iter.hasNext) {
val elem = iter.next()
println(elem) // 输出:1 2 3 4 5
}
2. for 循环遍历
Scala 语法糖,底层仍调用hasNext和next:
scala
val iter = List("a", "b", "c").iterator
for (elem <- iter) {
println(elem) // 输出:a b c
}
3. 转换为集合(慎用,会消耗迭代器)
迭代器是一次性的,转换为集合后迭代器会被耗尽:
scala
val iter = List(10,20,30).iterator
val newList = iter.toList // 迭代器耗尽,后续无法再调用next
println(newList) // 输出:List(10,20,30)
注意:迭代器耗尽后不可复用
scala
val iter = List(1,2).iterator
iter.next() // 获取1
iter.next() // 获取2
iter.hasNext // false,迭代器已耗尽
iter.next() // 抛出NoSuchElementException
三、Scala 迭代器的优点
- 惰性加载,节省内存迭代器不提前加载所有元素到内存,仅在调用
next时才获取元素,适合处理超大集合(如 GB 级数据),避免一次性加载所有数据导致 OOM。 - 统一的遍历接口所有 Scala 集合(List/Set/Map/Array 等)都实现了
iterator方法,迭代器提供了统一的遍历方式,无需关注集合底层实现。 - 减少中间对象创建迭代器的方法(如
map、filter)返回的仍是迭代器,而非新集合,避免频繁创建中间集合,提升性能。 - 适配流式处理结合惰性特性,迭代器天然适配 “按需处理” 的场景(如大数据流式计算),仅处理当前需要的元素。
四、Scala 迭代器的常见方法
Scala 迭代器提供了丰富的方法,可分为基础方法、转换方法、聚合方法三类:
| 类别 | 方法名 | 作用说明 |
|---|---|---|
| 基础方法 | hasNext: Boolean | 判断迭代器是否还有下一个元素 |
next(): T | 获取下一个元素,无元素时抛出NoSuchElementException | |
reset() | 部分迭代器支持重置(如BufferedIterator),恢复到初始状态(慎用,非所有迭代器支持) | |
| 转换方法 | map(f: T => S): Iterator[S] | 对每个元素应用函数f,返回新迭代器(惰性) |
filter(p: T => Boolean): Iterator[T] | 过滤出满足条件p的元素,返回新迭代器(惰性) | |
take(n: Int): Iterator[T] | 取前n个元素,返回新迭代器 | |
drop(n: Int): Iterator[T] | 跳过前n个元素,返回新迭代器 | |
zip(that: Iterator[S]): Iterator[(T, S)] | 与另一个迭代器 “拉链” 配对,返回元组迭代器(以短的迭代器长度为准) | |
flatMap(f: T => TraversableOnce[S]): Iterator[S] | 扁平化映射,拆解嵌套集合 | |
| 聚合方法 | foreach(f: T => Unit): Unit | 遍历每个元素并执行函数f(无返回值) |
foldLeft(init: S)(f: (S, T) => S): S | 从左到右聚合元素,初始值为init | |
sum/max/min | 求和 / 最大值 / 最小值(仅适用于数值类型迭代器) | |
toList/toSet/toMap | 转换为对应集合(耗尽迭代器) | |
| 其他方法 | isEmpty: Boolean | 判断迭代器是否为空(等效于!hasNext) |
exists(p: T => Boolean): Boolean | 判断是否存在满足条件p的元素 | |
forall(p: T => Boolean): Boolean | 判断所有元素是否都满足条件p |
常见方法示例
scala
val iter = List(1,2,3,4,5).iterator
// 1. take/drop
val takeIter = iter.take(2) // 取前2个元素:1,2
takeIter.foreach(println) // 输出:1 2
// 重置迭代器(重新创建)
val iter2 = List(1,2,3,4,5).iterator
val dropIter = iter2.drop(2) // 跳过前2个:3,4,5
dropIter.foreach(println) // 输出:3 4 5
// 2. zip
val iter3 = List(1,2,3).iterator
val strIter = List("a","b").iterator
val zipIter = iter3.zip(strIter)
zipIter.foreach(println) // 输出:(1,a) (2,b)
// 3. map + filter
val iter4 = List(1,2,3,4,5).iterator
val newIter = iter4.filter(_ % 2 == 0).map(_ * 2)
newIter.foreach(println) // 输出:4 8
// 4. foldLeft聚合
val iter5 = List(1,2,3).iterator
val sum = iter5.foldLeft(0)(_ + _)
println(sum) // 输出:6
关键注意点
-
迭代器是一次性的:一旦遍历(或转换为集合),迭代器会被耗尽,无法再次使用;
-
惰性特性:
map/filter等转换方法仅生成 “待执行” 的迭代器,直到调用next/foreach才真正计算; -
线程不安全:迭代器不支持多线程并发访问,需手动加锁或使用线程安全的迭代器实现。