Kotlin Iterators

An iterator walks through a collection one item at a time. Every for loop over a list, set, or map uses an iterator behind the scenes. Learning the iterator directly gives you finer control over the walk, including the power to remove items safely.

The Cursor on a Conveyor Belt

Imagine a conveyor belt carrying parcels past a worker. The worker looks at one parcel, picks it up, and the belt moves ahead. The worker never jumps backward and never sees the whole belt at once. An iterator behaves like that worker. A pointer sits before the first item and moves forward on demand.

  Pointer starts here
        |
        v
      [ A ]  [ B ]  [ C ]  [ D ]
        ^
     next() returns A, pointer moves to the gap before B

The Two Core Functions

  • hasNext() answers yes or no: does another item wait ahead?
  • next() returns the following item and moves the pointer.
fun main() {
    val fruits = listOf("Apple", "Banana", "Cherry")
    val iterator = fruits.iterator()

    while (iterator.hasNext()) {
        println(iterator.next())
    }
}

The loop prints Apple, Banana, and Cherry. Calling next() after the last item throws a NoSuchElementException, so always check hasNext() first.

The for Loop Shortcut

The compiler translates a for loop into the same iterator steps.

for (fruit in fruits) {
    println(fruit)
}

Both versions behave the same. The loop version needs less typing, and the manual version offers extra control.

Removing Items While Walking

Changing a list inside a normal for loop causes a ConcurrentModificationException. A mutable iterator avoids that problem. Its remove() function deletes the item returned by the latest next() call.

fun main() {
    val numbers = mutableListOf(1, 2, 3, 4, 5, 6)
    val iterator = numbers.iterator()

    while (iterator.hasNext()) {
        if (iterator.next() % 2 == 0) {
            iterator.remove()
        }
    }
    println(numbers)   // [1, 3, 5]
}
 Before:  [1] [2] [3] [4] [5] [6]
                |       |       |
 remove()      even    even    even
 After:   [1] [3] [5]

Walking Backward with ListIterator

A list offers a richer iterator. A ListIterator moves in both directions and reports positions.

val letters = listOf("A", "B", "C")
val it = letters.listIterator()

while (it.hasNext()) {
    println("${it.nextIndex()}: ${it.next()}")
}
while (it.hasPrevious()) {
    println(it.previous())
}

The first loop prints 0: A, 1: B, and 2: C. The second loop walks back and prints C, B, and A.

Walking a Map

A map holds pairs of keys and values. The iterator delivers one pair at a time.

val prices = mapOf("Tea" to 20, "Coffee" to 35)
for ((item, price) in prices) {
    println("$item costs $price")
}

Make Your Own Class Loopable

Any class that supplies an iterator() function marked operator works inside a for loop. A countdown timer shows the idea.

class Countdown(private val from: Int) {
    operator fun iterator(): Iterator<Int> {
        return object : Iterator<Int> {
            var current = from
            override fun hasNext() = current >= 0
            override fun next() = current--
        }
    }
}

fun main() {
    for (n in Countdown(3)) {
        print("$n ")   // 3 2 1 0
    }
}

The object keeps its own counter, so each loop starts fresh.

Iterator Types at a Glance

TypeMovesCan Remove
IteratorForwardNo
MutableIteratorForwardYes
ListIteratorBoth directionsNo
MutableListIteratorBoth directionsYes, plus add and set

For simple removal tasks, the function removeAll or removeIf offers a shorter route. Reach for a manual iterator when the walk needs custom control.