Kotlin: For-loop vs ForEach

With Kotlin, we can write loop for(i in a..b){} and we could also do (a..b).forEach{}. Which should we use?

Well, instead of arbitrary decide, or just use the seemingly more glamorous functional style, let’s do some pragmatic comparison.

Simple Loop

// For loop
for (i in 0..10) { println(i) }
// ForEach
(0..10).forEach { println(it) }

From the above, both looks similar, except for normal for has an extra i variable there.

Collection

// For loop
val list = listOf(1, 2, 3).filter( it == 2 )
for (i in list) { println(i) }
// ForEach
listOf(1, 2, 3).filter( it == 2 ).forEach { println(it) }

If the data source is an iterable collection, forEach would be better, as it could be chained together.

Continue

// For loop
for (i in 0 until 10 step 3) {
if (i == 6) continue
println(i)
}
// ForEach
(i in 0 until 10 step 3).forEach {
if (it == 6) return@forEach
println(it)
}

If you need continue, the forEach has the ugly looking return@forEach. For-loop is better here.

Break

// For loop
for (i in 0 until 10 step 3) {
if (i == 6) break
println(i)
}
// ForEach (result is wrong though)
(i in 0 until 10 step 3).forEach {
if (it == 6) return
println(it)
}

We could use break in For-loop, but for forEach, the closest it could try is return, which is not really correct, as it will exit the containing function totally, instead of continue outside of the for-loop. (let me know if you find a way to do so)

Performance

IntRange

println("ForLoop Time: " + measureNanoTime {
for (i in 0 until 10000) { doSomething() }
})

println("ForEach Time: " + measureNanoTime {
(0 until 10000).forEach { doSomething() }
}
)

Let’s looks at the result

ForLoop Time: 401199
ForEach Time: 5562190

When it is normal IntRange, using forEach uses 10x more time than For-loop.

List

val list = (1..10000).toList()

println("ForLoop Time: " + measureNanoTime {
for (i in list) { doSome() }
})

println("ForEach Time: " + measureNanoTime {
list.forEach { doSome() }
}
)

Let’s looks at the result

ForLoop Time: 1577558
ForEach Time: 1006187

If it is as list, using for-loop is slower than ForEach.

Sequence

val sequence = (1..10000).asSequence()

println("ForLoop Time: " + measureNanoTime {
for (i in sequence) { doSome() }
})

println("ForEach Time: " + measureNanoTime {
sequence.forEach { doSome() }
}
)

Let’s looks at the result

ForLoop Time: 2929793
ForEach Time: 1147545

For sequence, using for-loop is much slower than ForEach.

FYI, if you are interested to know what is sequence and list, refers to

Conclusion

  • If it is IntRange, use for-loop.
  • If it is collection (e.g. sequence or list), use forEach.
  • If it uses continue and break, use for-loop.

What if it needs continue and break but it is also a collection e.g. list or sequence?

for (i in list) {
if (toContinue(list[i])) continue
if (toBreak(list[i])) break
doSomething(i)
}

Don’t use forEach. Use normal functional operation like map, filter etc.

list.asSequence()
.filterNot { toContinue(it) }
.map { doSomething(it); it }
.first { toBreak(it) }

I hope this post is helpful to you. You could check out my other interesting topics here.

Follow me on medium, Twitter or Facebook for little tips and learning on Android, Kotlin etc related topics. ~Elye~