Iterators

For traversing collection elements, the Kotlin standard library supports the commonly used mechanism of iterators – objects that provide access to the elements sequentially without exposing the underlying structure of the collection. Iterators are useful when you need to process all the elements of a collection one-by-one, for example, print values or make similar updates to them.

Iterators can be obtained for inheritors of the Iterable<T> interface, including Set and List, by calling the iterator() function. Once you obtain an iterator, it points to the first element of a collection; calling the next() function returns this element and moves the iterator position to the following element if it exists. Once the iterator passes through the last element, it can no longer be used for retrieving elements; neither can it be reset to any previous position. To iterate through the collection again, create a new iterator.

  1. fun main() {
  2. //sampleStart
  3. val numbers = listOf("one", "two", "three", "four")
  4. val numbersIterator = numbers.iterator()
  5. while (numbersIterator.hasNext()) {
  6. println(numbersIterator.next())
  7. }
  8. //sampleEnd
  9. }

Another way to go through an Iterable collection is the well-known for loop. When using for on a collection, you obtain the iterator implicitly. So, the following code is equivalent to the example above:

  1. fun main() {
  2. //sampleStart
  3. val numbers = listOf("one", "two", "three", "four")
  4. for (item in numbers) {
  5. println(item)
  6. }
  7. //sampleEnd
  8. }

Finally, there is a useful forEach() function that lets you automatically iterate a collection and execute the given code for each element. So, the same example would look like this:

  1. fun main() {
  2. //sampleStart
  3. val numbers = listOf("one", "two", "three", "four")
  4. numbers.forEach {
  5. println(it)
  6. }
  7. //sampleEnd
  8. }

List iterators

For lists, there is a special iterator implementation: ListIterator. It supports iterating lists in both directions: forwards and backwards. Backward iteration is implemented by the functions hasPrevious() and previous(). Additionally, the ListIterator provides information about the element indices with the functions nextIndex() and previousIndex().

  1. fun main() {
  2. //sampleStart
  3. val numbers = listOf("one", "two", "three", "four")
  4. val listIterator = numbers.listIterator()
  5. while (listIterator.hasNext()) listIterator.next()
  6. println("Iterating backwards:")
  7. while (listIterator.hasPrevious()) {
  8. print("Index: ${listIterator.previousIndex()}")
  9. println(", value: ${listIterator.previous()}")
  10. }
  11. //sampleEnd
  12. }

Having the ability to iterate in both directions, means the ListIterator can still be used after it reaches the last element.

Mutable iterators

For iterating mutable collections, there is MutableIterator that extends Iterator with the element removal function remove(). So, you can remove elements from a collection while iterating it.

  1. fun main() {
  2. //sampleStart
  3. val numbers = mutableListOf("one", "two", "three", "four")
  4. val mutableIterator = numbers.iterator()
  5. mutableIterator.next()
  6. mutableIterator.remove()
  7. println("After removal: $numbers")
  8. //sampleEnd
  9. }

In addition to removing elements, the MutableListIterator can also insert and replace elements while iterating the list.

  1. fun main() {
  2. //sampleStart
  3. val numbers = mutableListOf("one", "four", "four")
  4. val mutableListIterator = numbers.listIterator()
  5. mutableListIterator.next()
  6. mutableListIterator.add("two")
  7. mutableListIterator.next()
  8. mutableListIterator.set("three")
  9. println(numbers)
  10. //sampleEnd
  11. }