Higher-order function — olyan függvény, amely egy másik függvényt paraméterként fogad el, vagy függvényt ad vissza eredményként. Kotlinban a függvények első osztályú objektumok: tárolhatók változókban, átadhatók argumentumként és visszatérhetők. A Kotlin dokumentáció (2026) szerint a higher-order functions átlagosan 30%-kal csökkentik a kódismétlést az imperatív megközelítésekhez képest. Higher-order function — a funkcionális stílus alapvető fogalma a modern fejlesztésben.
Főbb pontok
Higher-order function — olyan függvény, amely rendelkezik legalább az egyik két jellemzővel: egy másik függvény fogadása argumentumként vagy függvény visszaadása eredményként. A matematikában az ilyen függvényeket funkcionáloknak vagy operátoroknak nevezik. A programozásban 1958-ban jelentek meg a Lisp-ben, és kötelező részévé váltak minden modern nyelvnek — JavaScript, Python, Swift, Kotlin, Scala és Haskell. A Higher-order function lehetővé teszi az elvonatkoztatást egy konkrét művelettől és a viselkedés értékként való átadását.
A legfőbb különbség a higher-order function és a szokásos függvény között — a funkcionális típusú paraméter vagy a visszaadott funkcionális érték jelenléte. Kotlinban a funkcionális típus (ParamType) -> ReturnType formában íródik. Például az (Int) -> String típus egy olyan függvényt jelent, amely Int-et fogad el és String-et ad vissza. A () -> Unit típus egy paraméter nélküli függvényt jelöl, amely nem ad vissza hasznos értéket. Pontosan ez a típusrendszer teszi a higher-order functions típusbiztossá.
A higher-order function ellentéte — first-class function (első osztályú függvény). A First-class function azt jelenti, hogy egy függvény úgy használható, mint bármely más érték: hozzárendelhető változóhoz, tárolható gyűjteményben, átadható argumentumként. A Higher-order function olyan függvény, amely first-class functions-t használ a fogadáshoz vagy visszaadáshoz. A Kotlin mindkét koncepciót támogatja nyelvi szinten, további könyvtárak nélkül.
Kotlinban minden olyan függvény, amelynek legalább egy paramétere funkcionális típussal van deklarálva, vagy a visszatérési típusa funkcionális, automatikusan higher-order function-nek minősül. A fordító nem igényel speciális annotációt — elég megadni a (T) -> R típust az aláírásban. Egy ilyen függvény meghívásakor argumentumként vagy lambda kifejezés, vagy ::-n keresztül egy meglévő függvényre való hivatkozás, vagy egy változóban tárolt funkcionális érték kerül átadásra.
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
}
A listában az operate függvény két egész számot és az op paramétert fogadja el (Int, Int) -> Int típusban. A függvény törzse egy sorban meghívja az átadott műveletet. A main-ben az operate hívás átadja a { x, y -> x + y } lambdát — a Kotlin a trailing lambda szintaxisnak köszönhetően a zárójelek után helyezi el. Ha a lambda az utolsó argumentum lenne, teljesen ki lehetne vinni a zárójeleken kívülre, ami növeli a hívási láncok olvashatóságát.
A motorháztető alatt a Kotlin a higher-order function-t a Function interfészen keresztül fordítja le (Function2 két paraméter esetén). Minden lambda egy anonim osztállyá alakul, amely megvalósítja a megfelelő FunctionN interfészt. Ez azt jelenti, hogy a lambda létrehozása objektum allokációt von maga után minden művelethez. A többletterhelés csökkentésére a Kotlin támogatja az inline függvényeket, amelyek a higher-order function törzsét a hívás helyére illesztik be, kiküszöbölve az anonim osztály létrehozását.
Egy függvény argumentumként való átadása — a higher-order function használatának leggyakoribb mintája. Ahelyett, hogy osztályhierarchiát hozna létre polimorf metódussal, a programozó a szükséges viselkedést közvetlenül a felhasználás helyére adja át. Ez megvalósítja a Nyílt/Zárt Elvet (Open/Closed Principle) öröklődés nélkül: egy új művelet új lambdaként kerül hozzáadásra, nem pedig új alosztályként.
A nullable függvényekhez a Kotlin a ((T) -> R)? típust használja kérdőjellel a zárójelek után. Egy ilyen függvény csak null ellenőrzés után vagy a ?.invoke() operátoron keresztül hívható meg. A higher-order function aláírása egyértelműen jelzi, hogy a függvény átadása nem kötelező — a hívó kód elhagyhatja az argumentumot. Ez hasznos a callback-eknél és eseménykezelőknél opcionális viselkedéssel.
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]
}
A customFilter kiterjesztési függvény fogadja a predicate paramétert (T) -> Boolean funkcionális típussal. A ciklus belsejében minden elemre meghívja a predicate-et és összegyűjti a megfelelőeket. A main-ben a hívás átadja a { it % 2 == 0 } lambdát, ahol az it a lambda egyetlen paraméterének implicit neve. A higher-order function-nek köszönhetően a szűrési logika teljesen elkülönül a gyűjtemény bejárási mechanizmusától.
A higher-order function visszaadhat egy függvényt — ezt a mintát függvénygyárnak vagy viselkedésgenerátornak nevezik. A visszaadott függvény elkaphat (closure) változókat a külső láthatósági tartományból, megőrizve őket a hívások között. Ez lehetővé teszi konfigurálható kezelők és specializált műveletek létrehozását általános sablonok alapján.
Függvény visszaadásakor a Kotlin kikövetkezteti a visszaadott funkcionális típust ((T) -> R)? az aláírásból. A fordító ellenőrzi, hogy a törzsben lévő összes return kifejezés kompatibilis funkcionális értékeket ad-e vissza. Az elkapott változók a lambda objektumban tárolódnak és addig érhetők el, amíg létezik rá hivatkozás. Ez egy erős mechanizmus, de figyelmet igényel a memóriakezelésben.
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
}
A makeMultiplier függvény fogadja a factor-t és visszaadja a { x -> x * factor } lambdát, ahol a factor a külső tartományból (closure) van elkapva. Minden makeMultiplier hívásnál egy új függvény jön létre a saját factor értékével. A double és triple változók tárolják a visszaadott függvényeket és többször is meghívhatók. Ez a minta széles körben használatos HTTP kliensek konfigurálásában, dekorátorokban és middleware-ben.
A higher-order function és lambdák kombinált használata lehetővé teszi kifejező műveleti láncok építését köztes változók nélkül. A Kotlin szabványos könyvtára több tucat higher-order functions-t tartalmaz: let, run, apply, also, filter, map, flatMap, fold, reduce, forEach, groupBy és mások. Mindegyikük fogad egy lambdát és annak segítségével hajtja végre az adatátalakítást.
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]
}
A példában három higher-order functions lánca feldolgoz egy felhasználói listát. A filter fogad egy predikátumot, csak a nagykorú felhasználókat hagyja meg. A map minden felhasználót nagybetűkkel írt névvé alakít. A sorted növekvő sorrendbe rendezi az eredményt. Minden művelet fogad egy lambdát, és a Kotlin típusbiztonságot biztosít minden szakaszban. Higher-order function nélkül egy ciklust kellene írni if-fel, ideiglenes listákkal és kézi rendezéssel.
Gyakran ismételt kérdések
Higher-order function egy másik függvényt fogad el paraméterként vagy adja vissza azt. A szokásos függvény csak adatokkal — számokkal, karakterláncokkal, objektumokkal — dolgozik. A higher-order function viselkedéssel dolgozik, logikát adva át argumentumként.
Igen, az inline módosító kiküszöböli az anonim osztály létrehozásának többletterhelését a lambda számára. A crossinline vagy noinline segítségével szabályozható, hogy mely lambdák kerüljenek beillesztésre és melyek maradjanak objektumok.
A paraméter nélküli és visszatérési érték nélküli függvény típusa () -> Unit. Az egy T típusú paraméterrel rendelkező és R-t visszaadó függvény (T) -> R formában íródik. Két paraméter esetén — (T, U) -> R és így tovább 22 argumentumig.
A Lambda — tömör jelölés { args -> body }, az anonim függvény — fun(args): ReturnType { body }. A lambdának nem lehet return címke nélkül, az anonim függvénynek igen. Mindkettő átadható a higher-order function számára.
Kerülje a higher-order function-t forró ciklusokban inline nélkül — minden lambda létrehoz egy objektumot. Kritikus teljesítményhez használjon inline fun-t. Továbbá ne használja túl a lambdák mély beágyazását — ez csökkenti az olvashatóságot.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is