KotlinのforEachについて

採用はこちら

Kotlinの forEach は、コレクションや配列などの要素を1つずつ取り出して、順番に処理するための関数です。

たとえば、リストの中身を順番に表示したいときに使えます。

val fruits = listOf("apple", "banana", "orange")

fruits.forEach {
    println(it)
}

このコードでは、applebananaorange の順に表示されます。

目次

基本構文

collection.forEach { element ->
    処理
}

引数が1つだけなら、名前を省略して it が使えます。

val numbers = listOf(1, 2, 3)

numbers.forEach {
    println(it)
}

これは次と同じ意味です。

numbers.forEach { number ->
    println(number)
}

it と明示的な名前の使い分け

短い処理なら it で十分ですが、意味が分かりにくくなるなら名前を付けたほうが読みやすいです。

users.forEach { user ->
    println(user.name)
}

forEach が使える主な対象

forEach は代表的に次のようなものに使えます。

List

val names = listOf("Taro", "Hanako", "Jiro")

names.forEach {
    println(it)
}

Set

val numbers = setOf(10, 20, 30)

numbers.forEach {
    println(it)
}

ただし、Set は重複しない要素の集合であり、List のような「順序付きコレクション」とは性質が異なります。

実装によっては見かけ上順番どおりに見えることもありますが、概念としては順序を前提にしないほうが安全です。

配列

val arr = arrayOf("A", "B", "C")

arr.forEach {
    println(it)
}

Map

Map の場合は、各要素が Map.Entry として扱われます。

val scores = mapOf("Alice" to 80, "Bob" to 90)

scores.forEach {
    println("${it.key}: ${it.value}")
}

分解代入で書くこともできます。

scores.forEach { (name, score) ->
    println("$name: $score")
}

forEachIndexed との違い

forEach は要素そのものを順番に処理します。

一方で、インデックスも必要な場合forEachIndexed を使います。

val fruits = listOf("apple", "banana", "orange")

fruits.forEachIndexed { index, fruit ->
    println("$index: $fruit")
}

出力

0: apple
1: banana
2: orange

使い分け

  • 要素だけ必要 → forEach
  • 添字も必要 → forEachIndexed

forEachfor 文の違い

forEachfor 文も、どちらも繰り返し処理に使えます。

for

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

forEach

fruits.forEach {
    println(it)
}

forEach の特徴

  • 短く書きやすい
  • Kotlinらしい書き方になる
  • mapfilter などの関数型スタイルと相性がよい

for 文の特徴

  • breakcontinue をそのまま使える
  • 複雑な分岐や途中終了が分かりやすい
  • 制御構文として直感的

つまり、単純に各要素へ同じ処理をしたいなら forEach途中終了や複雑な制御が必要なら for が向いています。

forEachbreak / continue

ここはとても重要です。

forEach のラムダの中では、for 文のように breakcontinue をそのまま書けません

なぜなら、forEach はループ構文そのものではなく、関数にラムダを渡している形だからです。

continue に近いことをしたい場合

たとえば、奇数をスキップして偶数だけ表示したいとします。

for 文なら

for (n in listOf(1, 2, 3, 4, 5)) {
    if (n % 2 != 0) continue
    println(n)
}

forEach なら

listOf(1, 2, 3, 4, 5).forEach {
    if (it % 2 != 0) return@forEach
    println(it)
}

return@forEach は、その回のラムダ処理だけを終えて、次の要素へ進む動きです。

これは continue に近い挙動 です。

break に近いことをしたい場合

たとえば、3 が出たらそこで処理全体を止めたい場合です。

for 文なら自然

for (n in listOf(1, 2, 3, 4, 5)) {
    if (n == 3) break
    println(n)
}

forEach ではどうか

forEach には、break に対応する直接的な書き方はありません

そのため、途中終了したい処理では、普通の for 文を使うほうが自然で分かりやすいです。

return の挙動に注意

Kotlin の forEach では、return の意味が少し特殊になることがあります。

特に、関数の中で forEach を使うときは注意が必要です。

fun printNumbers() {
    listOf(1, 2, 3, 4, 5).forEach {
        if (it == 3) return
        println(it)
    }
    println("終了")
}

この場合、it == 3 になったとき、forEach だけでなく printNumbers() 自体が終了します。

出力

1
2

終了 は表示されません。

なぜそうなるのか

これは、forEachinline 関数 だからです。

Kotlin では、inline 関数に渡したラムダの中でラベルなしの return を使うと、外側の関数から戻ることがあります。

このような戻り方を、non-local return と呼びます。

forEach だけ抜けたいわけではない場合

forEach の今の1回だけを終えて、次へ進みたい」なら return@forEach を使います。

fun printNumbers() {
    listOf(1, 2, 3, 4, 5).forEach {
        if (it == 3) return@forEach
        println(it)
    }
    println("終了")
}

出力

1
2
4
5
終了

ここでの return@forEach は、その要素の処理だけを終えるものです。

ラベル付きで書く方法

forEach には独自ラベルを付けることもできます。

fun sample() {
    listOf(1, 2, 3, 4, 5).forEach myLabel@{
        if (it == 3) return@myLabel
        println(it)
    }
    println("done")
}

これは return@forEach と似た意味です。

ただし、通常は return@forEach のほうが分かりやすいので、まずはこちらを使えば十分です。

forEach は値を返さない

forEach各要素に対して処理を実行するための関数であり、変換結果のリストを返す関数ではありません

val numbers = listOf(1, 2, 3)

val result = numbers.forEach {
    println(it)
}

この result の型は Unit です。

つまり forEach は、

  • 表示する
  • ログを出す
  • 保存する
  • 集計用の変数を更新する

といった、副作用を伴う処理に向いています。

変換したいなら map

forEachmap はよく混同されますが、役割はまったく違います。

forEach

各要素に対して処理を実行するだけ

val numbers = listOf(1, 2, 3)

numbers.forEach {
    println(it * 2)
}

map

変換結果を新しいリストとして返す

val numbers = listOf(1, 2, 3)

val doubled = numbers.map {
    it * 2
}

println(doubled)

出力

[2, 4, 6]

判断基準

  • 何かを表示したい、保存したい、処理したい → forEach
  • 新しいコレクションを作りたい → map

forEach のよくある使い方

1つずつ表示する

val items = listOf("pen", "notebook", "eraser")

items.forEach {
    println(it)
}

条件付きで処理する

val numbers = listOf(1, 2, 3, 4, 5)

numbers.forEach {
    if (it % 2 == 0) {
        println("偶数: $it")
    }
}

オブジェクトのプロパティを使う

data class User(val name: String, val age: Int)

val users = listOf(
    User("Alice", 20),
    User("Bob", 25)
)

users.forEach { user ->
    println("${user.name} is ${user.age} years old")
}

集計に使う例

val numbers = listOf(10, 20, 30)
var sum = 0

numbers.forEach {
    sum += it
}

println(sum)

この書き方は正しいですが、集計が目的なら sum()fold() のような専用関数のほうが意図が明確な場合もあります

forEach を使わないほうがよい場面

次のようなケースでは、無理に forEach を使うより for 文のほうが読みやすいことがあります。

途中で打ち切りたい

for (item in items) {
    if (item == target) break
}

複雑な条件分岐がある

for (item in items) {
    if (condition1) {
        println("A")
    } else if (condition2) {
        println("B")
    } else {
        println("C")
    }
}

ループ制御を細かく書きたい

この場合も、制御構文である for 文のほうが意図が伝わりやすいです。

初心者がハマりやすいポイント

forEach は新しいリストを返さない

val result = listOf(1, 2, 3).forEach {
    it * 2
}

この result は変換後のリストにはなりません。

forEach の戻り値は Unit です。

変換したいなら map を使います。

ラベルなし return で外側の関数が終わることがある

fun test() {
    listOf(1, 2, 3).forEach {
        if (it == 2) return
        println(it)
    }
    println("end")
}

この場合、2 に来た時点で test() 全体が終了します。

break の代わりには向いていない

forEach には break に相当する直接的な書き方がありません。

途中終了したい処理では for 文のほうが素直です。

実務での使い分け

forEach が向いている場面

  • 各要素に同じ処理を順にしたい
  • 表示、ログ出力、保存などの副作用が中心
  • 短くシンプルに書きたい

for 文が向いている場面

  • break を使いたい
  • continue を分かりやすく書きたい
  • ループ制御が複雑
  • 可読性を優先したい

まとめ

Kotlin の forEach は、コレクションや配列などの各要素に対して順番に処理を実行する関数です。

覚えておくべきポイントを整理すると、次の通りです。

  • forEach は各要素を順番に処理する
  • 引数が1つなら it が使える
  • インデックスも必要なら forEachIndexed
  • forEachUnit を返す
  • 新しいコレクションを作りたいなら map
  • ラムダ内で break / continue はそのまま使えない
  • return@forEachcontinue に近い動き
  • break に対応する直接的な書き方はないので、途中終了したいなら for 文が自然
  • ラベルなし return は、外側の関数から戻ることがある

最後にシンプル比較

forEach

listOf(1, 2, 3).forEach {
    println(it)
}

forEachIndexed

listOf("a", "b", "c").forEachIndexed { index, value ->
    println("$index: $value")
}

map

val result = listOf(1, 2, 3).map {
    it * 2
}
println(result)

for

for (n in listOf(1, 2, 3)) {
    if (n == 2) break
    println(n)
}

以上、KotlinのforEachについてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次