Iterator HasNext Calls Next

ID

kotlin.iterator_has_next_calls_next

Severity

high

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Code Smell

Language

Kotlin

Tags

correctness, reliability

Description

Reports calls to next() inside a hasNext() override. Calling next() from within hasNext() advances the iterator on every existence check, silently skipping elements and corrupting the iteration.

Rationale

The Iterator contract specifies that hasNext() must be idempotent — calling it multiple times without an intervening next() must not change state. If hasNext() calls next() internally, the following standard loop silently skips every other element:

// Bad
class IntIter(private val items: List<Int>) : Iterator<Int> {
    private var index = 0

    override fun hasNext(): Boolean {
        return next() != null  // FLAW — advances iterator on every check
    }

    override fun next(): Int = items[index++]
}

// Using it: prints only even-indexed elements
val it = IntIter(listOf(1, 2, 3, 4))
while (it.hasNext()) {      // consumes items[0]=1
    println(it.next())      // then consumes items[1]=2 — skips 1
}
// prints 2, 4 instead of 1, 2, 3, 4

// Good
override fun hasNext(): Boolean = index < items.size  // no side-effects

Remediation

Rewrite hasNext() to check the iterator’s internal state (position, backing collection size, peek buffer) without consuming an element. If look-ahead is necessary, read one element ahead into a nullable field and check it there — but never via a next() call in hasNext().

References