5.3.3 遍历List元素
使用Iterator迭代器
我们以集合 val list = listOf(0,1, 2, 3, 4, 5, 6,7,8,9)
为例,使用Iterator迭代器遍历列表所有元素的操作:
>>> val list = listOf(0,1, 2, 3, 4, 5, 6,7,8,9)
>>> list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> val iterator = list.iterator()
>>> iterator
java.util.AbstractList$Itr@438bad7c
>>> while(iterator.hasNext()){
... println(iterator.next())
... }
0
1
2
3
4
5
6
7
8
9
迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
Kotlin中的Iterator功能比较简单,并且只能单向移动:
(1)调用iterator()函数,容器返回一个Iterator实例。iterator()函数是kotlin.collections.Iterable
中的函数, 被Collection继承。
(2)调用hasNext()函数检查序列中是否还有元素。
(3)第一次调用Iterator的next()函数时,它返回序列的第一个元素。依次向后递推,使用next()获得序列中的下一个元素。
当我们调用到最后一个元素,再次调用next()
函数,会抛这个异常java.util.NoSuchElementException
。代码示例:
>>> val list = listOf(1,2,3)
>>> val iter = list.iterator()
>>> iter
java.util.AbstractList$Itr@3abfe845
>>> iter.hasNext()
true
>>> iter.next()
1
>>> iter.hasNext()
true
>>> iter.next()
2
>>> iter.hasNext()
true
>>> iter.next()
3
>>> iter.hasNext()
false
>>> iter.next()
java.util.NoSuchElementException
at java.util.AbstractList$Itr.next(AbstractList.java:364)
我们可以看出,这里的Iterator的实现是在AbstractList
中的内部类IteratorImpl
:
private open inner class IteratorImpl : Iterator<E> {
protected var index = 0
override fun hasNext(): Boolean = index < size
override fun next(): E {
if (!hasNext()) throw NoSuchElementException()
return get(index++)
}
}
通过这个实现源码,我们可以更加清楚地明白Iterator的工作原理。
其中,NoSuchElementException()
这个类是java.util.NoSuchElementException
的类型别名:
@kotlin.SinceKotlin public typealias NoSuchElementException = java.util.NoSuchElementException
```#### 使用`forEach`遍历List元素
这个`forEach`函数定义如下:
```kotlin
@kotlin.internal.HidesMembers
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
for (element in this) action(element)
}
它是package kotlin.collections
包下面的Iterable的扩展内联函数。它的入参是一个函数类型:
action: (T) -> Unit
关于函数式编程,我们将在后面章节中学习。
这里的forEach
是一个语法糖。实际上forEach
在遍历List对象的时候,仍然使用的是iterator迭代器来进行循环遍历的。
>>> val list = listOf(1,2,3)
>>> list
[1, 2, 3]
>>> list.forEach{
... println(it)
... }
1
2
3
当参数只有一个函数的时候,括号可以省略不写。
也就是说,这里面的forEach函数调用的写法,实际上跟下面的写法等价:
list.forEach({
println(it)
})
我们甚至还可以直接这样写:
>>> list.forEach(::println)
其中,::
是函数引用符。