Lambda(ラムダ)は、コンパクトな式 { 引数 -> 本体 } として表される無名関数です。Kotlinでは、ラムダは高階関数に振る舞いを渡す主要な方法であり、個別の関数を宣言せずに簡潔な構文を提供します。Kotlinのドキュメント(2026年)によると、一般的なプロジェクトの70%以上の高階関数がラムダとともに呼び出されています。Lambdaは、最小限の構文ノイズで関数型スタイルのコードを記述することを可能にします。
重要なポイント
Lambda(ラムダ式)は、宣言ではなく式として定義される無名関数です。この用語はアロンゾ・チャーチのラムダ計算(1936年)に由来します。プログラミングにおいて、ラムダは値として渡したり、変数に格納したり、後で呼び出したりできるコードのブロックです。Kotlinでは、ラムダは常に中括弧 { } で囲まれ、引数は -> アローによって本体から区切られます。
ラムダは通常の関数と異なり、名前や fun キーワードがありません。これにより、追加の宣言でコードを散らかすことなく、使用時点で直接振る舞いを宣言できます。Kotlinコンパイラはコンテキストから引数の型を推論するため、多くの場合で型を省略できます。ラムダは関数型 (T) -> R のシンタックスシュガーです。すべてのラムダには対応する関数型があります。
Kotlinにおけるラムダの主な用途は、高階関数に渡すことです。標準ライブラリはあらゆる場所でラムダを使用しています:filter { it > 0 }、map { it.uppercase() }、forEach { println(it) }。ラムダはイベントリスナー、コールバック、apply や run によるオブジェクト設定器にも使用され、無名クラスと比較してコードをより宣言的にします。
Kotlinにおけるラムダ式の完全な形式:{ 引数 -> ラムダ本体 }。引数はカンマで区切って列挙され、その後にアローと本体(1つ以上の式)が続きます。本体に複数の行が含まれる場合、最後の式が戻り値になります。関数が最後の引数としてラムダを受け取る場合、呼び出し括弧の外に移動できます。
val sum: (Int, Int) -> Int = { a, b -> a + b }
// コンテキストから推論される型
val sumShort = { a: Int, b: Int -> a + b }
// Lambda呼び出し
val result = sum(5, 3) // 8
println(result)
変数 sum は明示的な関数型 (Int, Int) -> Int で宣言され、ラムダ { a, b -> a + b } で初期化されています。sumShort の場合、型はラムダ内で指定され、変数の型は推論されます。どちらの形式も同等です。ラムダの呼び出しは通常の関数の呼び出しと同じです — sum(5, 3) 構文を使用します。引数のないラムダは { body } と書き、1つの引数を持つものは { it -> it * 2 } または単に { it * 2 } と書きます。
ラムダがちょうど1つの引数を受け取る場合、Kotlinは暗黙の名前 it を提供します。これにより、左側で引数を宣言する必要がなくなります。開発者はラムダ本体のみを書き、it を使用して単一のパラメータにアクセスします。この構文は、コレクション処理チェーンにおいて特に便利で、it は現在の要素を指します。
val numbers = listOf(1, 2, 3, 4, 5)
// 明示的なパラメータ名
val squaredExplicit = numbers.map { n -> n * n }
// 暗黙の it
val squared = numbers.map { it * it }
// it でのフィルタリング
val even = numbers.filter { it % 2 == 0 }
println(squared) // [1, 4, 9, 16, 25]
例では、map { it * it } は n -> を宣言する代わりに it を使用しています。Kotlinは単一のラムダパラメータに対して自動的に it を割り当てます。ラムダが2つ以上の引数を受け取る場合、it は作成されず — すべてのパラメータを明示的に宣言する必要があります。ネストされたラムダの読みやすさを向上させるには、パラメータに意味のある名前を付け、短い1行の述語でのみ it を使用するのが良いでしょう。
Trailing lambda は、最後のラムダ引数を関数呼び出し括弧の外に移動できるKotlinの構文機能です。これにより、コードが組み込みの言語構造のように見えます。ラムダが唯一の引数である場合、括弧は完全に省略できます。このアプローチは標準ライブラリやDSLで積極的に使用されています。
// 標準呼び出し
thread(block = {
println("スレッドからのこんにちは")
})
// Trailing lambda版
thread {
println("スレッドからのこんにちは")
}
// trailing lambdaでの繰り返し
repeat(3) { index ->
println("反復 $index")
}
// 複数行ラムダでの実行
val config = run {
val host = "localhost"
val port = 8080
"$host:$port"
}
thread 関数は最後の引数として Runnable を受け取ります。trailing lambda のおかげで、ラムダを括弧の外に渡すことができ、視覚的にコードブロックのように見えます。repeat 関数は反復回数とインデックス付きのラムダを受け取ります。run は、複数行のラムダが最後の式で返される値を計算する高階関数の例です。run() の周りの括弧は、ラムダが唯一の引数の場合に省略できます。
変数キャプチャ(クロージャ)は、ラムダが外部スコープで宣言された変数にアクセスする機能です。Kotlinでは、ラムダは var 変数を読み取り・変更でき、周囲のコンテキストから val 変数を読み取ることもできます。キャプチャされた変数はライフサイクル全体にわたってラムダとともに保存され、状態を持つ関数を作成できます。
fun makeCounter(): () -> Int {
var count = 0
return {
count++ // キャプチャ回数
}
}
fun main() {
val counter = makeCounter()
println(counter()) // 0
println(counter()) // 1
println(counter()) // 2
}
makeCounter 関数はローカル変数 count を宣言し、ラムダ { count++ } を返します。makeCounter が実行を完了した後でも、返されたラムダはクロージャを通じて count への参照を保持します。counter() を呼び出すたびに現在の値がインクリメントされて返されます。クロージャメカニズムは、カリー化、関数ファクトリ、メモ化の基盤です。可変変数をキャプチャすると並行実行時に予期しない動作を引き起こす可能性があることを覚えておくことが重要です。
よくある質問
Lambda は無条件の return をサポートしていません — ラベルなしの return は外部関数に制御を戻します。ラムダを終了するには、return@label を使用します。ここで label はラムダが渡された高階関数の名前です。
無名関数 は fun(a: Int): Int { return a * 2 } のように書き、ラベルなしの return をサポートします。ラムダ { a -> a * 2 } は構文が短いですが、早期終了には return@label が必要です。
ラムダが引数を受け取らない場合、アローは省略されます:{ body() }。1つの引数を受け取るが使用しない場合は、アンダースコアでパラメータを無視して { _ -> body() } と書きます。
はい、インライン化されていない関数に渡されるすべてのラムダは 無名クラス のインスタンスを作成します。インライン関数の場合、ラムダはオブジェクトを作成せずに呼び出しサイトにインライン化されます。キャプチャしないラムダはシングルトンオブジェクトとしてキャッシュされます。
Kotlinの return は、fun で宣言された最も近い関数に属するジャンプ演算子です。ラムダは関数(fun)ではなく、式です。したがって、ラムダ内のラベルなしの return は、外部の包含関数からの戻りとして扱われます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。