Higher-order functionは、別の関数をパラメータとして受け取ったり、関数を結果として返す関数です。Kotlinでは、関数はファーストクラスのオブジェクトです:変数に保存したり、引数として渡したり、返したりできます。Kotlinドキュメント (2026)によると、higher-order functionsは従来のきれいてきなアプローチと比較して、コードの重複を平均30%減らします。Higher-order functionは、現代のソフトウェア開発における関数的スタイルの基本的な概念です。
ポイント
Higher-order functionは、二つの特徴のうち少なくとも一つを持つ関数です:別の関数を引数として受け取るか、関数を結果として返すかです。数学では、このような関数は関数と呼ばれます。プログラミングでは、1958年にLispで登場し、すべての現代言語(JavaScript、Python、Swift、Kotlin、Scala、Haskell)で必須の要素となりました。Higher-order functionは、特定の操作から抽象化し、行動を値として渡すことを可能にします。
Higher-order functionと普通の関数の主な違いは、関数型を持つパラメータまたは返される関数型の値の存在です。Kotlinでは、関数型は (ParamType) -> ReturnType と書きます。例えば、型 (Int) -> String は Intを受け取って String を返す関数ゑ味します。型 () -> Unit はパラメータなしで有用な値を返さない関数を表します。この型システムによって、higher-order functionsは型安全になります。
Higher-order functionの反対は first-class functionです。First-class functionとは、関数を他の値と同様に使用できることを意味します:変数に代入したり、コレクションに保存したり、引数として渡したりできます。Higher-order functionは、受け取ったり返したりするために first-class functions を使用する関数です。Kotlinは追加ライブラリなしで言語レベルで両方の概念をサポートしています。
Kotlinでは、少なくとも一つのパラメータが関数型で宣言されているか、または戻り型が関数型である関数は、自動的に higher-order function とみなされます。コンパイラは特別な注釈を必要としません—シグネチャに (T) -> R を指定すれば十分です。このような関数を呼び出す際、引数はラムダ式、::を使った既存関数への参照、または変数に保存された関数型の値です。
fun operate(a: Int, b: Int, op: (Int, Int) -> Int): Int {
return op(a, b)
}
fun main() {
val sum = operate(10, 20) { x, y -> x + y }
println(sum) // 30
}
リストで、operate関数は二つの整数と型 (Int, Int) -> Int の op パラメータを受け取ります。関数の本体は一行で渡された操作を呼び出します。mainで、operateの呼び出しはラムダ { x, y -> x + y } を渡します—Kotlinはトレーリングラムダ構文によりこれを括弧の後に置きます。ラムダが最終引数であれば、それを完全に括弧の外に移動でき、呼び出しチェーンの読みやすさが向上します。
内部的に、Kotlinは Functionインターフェイスを通じて higher-order functions をコンパイルします。それぞれのラムダは、対応する FunctionN インターフェイスを実装する匿名クラスに変換されます。これは、ラムダの作成が操作ごとにオブジェクトの割り当てを意味することを意味します。オーバーヘッドを減らして、Kotlinは inline関数をサポートしており、呼び出しサイトで higher-order function の本体を置き換え、匿名クラスの作成を廃止します。
関数を引数として渡すのは、higher-order functionsの最も一般的なパターンです。ポリモーフィックメソッドを持つクラス階層を作る代わりに、ディベロッパーは必要な行動を使用ポイントに直接渡します。これによって、継承なしでオープン/クローズド原則が実現されます:新しい操作は新しいサブクラスではなく、新しいラムダとして追加されます。
null可能な関数には、Kotlinは括弧の後に疑問笙を付けた ((T) -> R)? 型を使用します。このような関数は、nullチェック後か ?.invoke() 演算子を使ってのみ呼び出せます。この場合、higher-order functionのシグネチャは、関数を渡すことがオプションツールであることを明示的に示します—呼び出し側のコードは引数を省略できます。これは、オプションの行動を持つコールバックやイベントハンドラに便利です。
fun <T> List<T>.customFilter(
predicate: (T) -> Boolean
): List<T> {
val result = mutableListOf<T>()
for (item in this) {
if (predicate(item)) result.add(item)
}
return result
}
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
val even = numbers.customFilter { it % 2 == 0 }
println(even) // [2, 4]
}
拡張関数 customFilterは、関数型 (T) -> Boolean の predicate パラメータを受け取ります。ループ内で、各要素に対して predicate を呼び出し、一致する要素を集めます。mainでの呼び出しはラムダ { it % 2 == 0 } を渡します。Higher-order functionsにより、フィルタリングロジックはコレクションのトラバースル機構から完全に立ち切られています。
Higher-order functionは関数を返すことができます—このパターンは関数ファクトリまたは行動生成器と呼ばれます。返された関数は、外部スコープから変数をキャプチャし、呼び出しの間で保持できます。これにより、構成可能なハンドラや、一般的なテンプレートに基づく専門化された操作を作成できます。
関数を返す際、Kotlinはシグネチャから返される関数型 ((T) -> R)? を推論します。コンパイラは、本体内のすべての return 式が互換性のある関数型の値を返すことを確認します。キャプチャされた変数はラムダオブジェクトに保存され、その参照が存在する限りアクセス可能です。これは強力なメカニズムですが、メモリ管理に注意が必要です。
fun makeMultiplier(factor: Int): (Int) -> Int {
return { x -> x * factor }
}
fun main() {
val double = makeMultiplier(2)
val triple = makeMultiplier(3)
println(double(5)) // 10
println(triple(5)) // 15
}
makeMultiplier関数は factor を受け取り、ラムダ { x -> x * factor } を返します。makeMultiplierの呼び出しごとに、固有の factor 値を持つ新しい関数が作成されます。変数 double と triple は返された関数を保存し、何度でも呼び出せます。このパターンは、HTTPクライアント構成、デコレータ、ミドルウェアで広く使用されています。
Higher-order functionsとラムダを組み合わせると、中間変数なしで表現豊かな操作チェーンを構築できます。Kotlin標準ライブラリには、多数の higher-order functions が含まれています:let、run、apply、also、filter、map、flatMap、fold、reduce、forEach、groupBy、その他。それぞれがラムダを受け取り、データ変換を行います。
data class User(val name: String, val age: Int)
fun main() {
val users = listOf(
User("Alice", 25),
User("Bob", 17),
User("Charlie", 30)
)
val result = users
.filter { it.age >= 18 }
.map { it.name.uppercase() }
.sorted()
println(result) // [ALICE, CHARLIE]
}
例では、3つの higher-order functions のチェーンがユーザーリストを処理します。filterは述語を受け取り、成人だけを残します。mapは各ユーザーを大文字の名前に変換します。sortedは結果を昇順に並べ替えます。各操作はラムダを受け取り、Kotlinは各階屡で型の安全性を確保します。Higher-order functionsがなければ、ifや一時リスト、マニュアルのソートを使ったループを書く必要があります。
よくある質問
Higher-order functionは、別の関数をパラメータとして受け取るか、関数を返します。普通の関数はデータ(数値、文字列、オブジェクト)でのみ動作します。Higher-order functionは行動で動作し、ロジックを引数として渡します。
はい、inline修飾子はラムダの匿名クラス作成のオーバーヘッドを解消します。crossinlineやnoinlineを使用すると、どのラムダをインラインし、どれをオブジェクトのままにするかを制御できます。
パラメータなしで戻り値のない関数の型は () -> Unit です。一つのパラメータ T と戻り値 R を持つ関数は (T) -> R と書きます。二つのパラメータの場合は (T, U) -> R 、22つの引数まで同様です。
ラムダは簡潔な表記法 { args -> body } で、匿名関数は fun(args): ReturnType { body } です。ラムダはラベルなしで return を使えませんが、匿名関数は使えます。両方とも higher-order function に渡せます。
inlineなしのホットループでは higher-order functions を避けてください—各ラムダがオブジェクトを作成します。パフォーマンスが重要なコードでは、inline funを使用してください。また、深くネストされたラムダの乾用は避けてください—可読性が低下します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。