ForEach On Range
ID |
kotlin.foreach_on_range |
Severity |
low |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Code Smell |
Language |
Kotlin |
Tags |
best-practice, performance |
Description
Reports forEach calls on IntRange, LongRange, CharRange, and related progression
types. Iterating a range with forEach forces the JVM to allocate an Iterator that
boxes each primitive value, whereas a for loop over the same range compiles to a
primitive counter loop with no heap allocation.
Rationale
In Kotlin, (1..10).forEach { … } calls Iterable<Int>.forEach, which requires an
Iterator<Int> backed by boxed Int objects. A for loop over the same range uses
the specialized IntIterator protocol and is compiled directly to a JVM bytecode for
counter — no Iterator object is allocated and no boxing occurs. On hot paths this
difference can be significant.
// Bad
(1..100_000).forEach { process(it) }
(1 until size).forEach { list.add(it) }
// Good
for (i in 1..100_000) process(i)
for (i in 1 until size) list.add(i)
Remediation
Replace the forEach call with a for loop. The transformation is mechanical and
preserves all semantics.