Higher-order function: czym jest, cechy i przykłady w Kotlin

Autor: IT Sectr Opublikowano: 2026-06-23 Czas czytania: 8 min

Higher-order function — to funkcja, która przyjmuje inną funkcję jako parametr lub zwraca funkcję w wyniku. W Kotlin funkcje są obiektami pierwszej klasy: można je przechowywać w zmiennych, przekazywać jako argumenty i zwracać. Według dokumentacji Kotlin (2026), higher-order functions redukują powielanie kodu średnio o 30% w porównaniu z podejściami imperatywnymi. Higher-order function — fundamentalna koncepcja stylu funkcyjnego w nowoczesnym programowaniu.

Najważniejsze

  • Higher-order function — funkcja przyjmująca inną funkcję jako parametr lub zwracająca ją
  • Typ funkcyjny (T) -> R — podstawa deklarowania parametrów-funkcji w sygnaturze
  • Wyrażenie lambda — zwarty sposób przekazywania funkcji do higher-order function
  • Przekazywanie zachowania pozwala parametryzować operacje bez dziedziczenia i interfejsów
  • Zwracanie funkcji z higher-order function stosowane jest w fabrykach i domknięciach

Czym jest higher-order function?

Higher-order function — to funkcja posiadająca co najmniej jedną z dwóch cech: przyjmowanie innej funkcji jako argumentu lub zwracanie funkcji jako wyniku. W matematyce takie funkcje nazywane są funkcjonałami lub operatorami. W programowaniu pojawiły się w Lisp w 1958 roku i stały się obowiązkową częścią wszystkich współczesnych języków — JavaScript, Python, Swift, Kotlin, Scala i Haskell. Higher-order function pozwala abstrahować od konkretnej operacji i przekazywać zachowanie jako wartość.

Kluczowa różnica między higher-order function a zwykłą funkcją — obecność parametru z typem funkcyjnym lub zwracanej wartości funkcyjnej. W Kotlin typ funkcyjny zapisuje się jako (ParamType) -> ReturnType. Na przykład typ (Int) -> String oznacza funkcję przyjmującą Int i zwracającą String. Typ () -> Unit oznacza funkcję bez parametrów, niezwracającą użytecznej wartości. To właśnie ten system typów sprawia, że higher-order function są bezpieczne typowo.

Przeciwieństwem higher-order function jest first-class function (funkcja pierwszej klasy). First-class function oznacza, że funkcję można używać jak każdą inną wartość: przypisać do zmiennej, przechowywać w kolekcji, przekazywać jako argument. Higher-order function — to funkcja, która wykorzystuje first-class functions do przyjmowania lub zwracania. Kotlin obsługuje obie koncepcje na poziomie języka bez dodatkowych bibliotek.

Jak działa higher-order function w Kotlin?

W Kotlin każda funkcja, która ma co najmniej jeden parametr zadeklarowany z typem funkcyjnym lub typ zwracany jest funkcyjny, automatycznie jest uważana za higher-order function. Kompilator nie wymaga specjalnej adnotacji — wystarczy podać (T) -> R w sygnaturze. Przy wywołaniu takiej funkcji argumentem przekazywane jest albo wyrażenie lambda, albo referencja do istniejącej funkcji przez ::, albo wartość funkcyjna zapisana w zmiennej.

kotlin
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
}

W listingu funkcja operate przyjmuje dwie liczby całkowite i parametr op typu (Int, Int) -> Int. Ciało funkcji w jednej linii wywołuje przekazaną operację. W main wywołanie operate przekazuje lambdę { x, y -> x + y } — Kotlin umieszcza ją po nawiasach dzięki składni trailing lambda. Gdyby lambda była ostatnim argumentem, można by ją całkowicie wynieść poza nawiasy, co zwiększa czytelność łańcuchów wywołań.

Pod maską Kotlin kompiluje higher-order function przez interfejs Function (Function2 dla dwóch parametrów). Każda lambda zamienia się w anonimową klasę implementującą odpowiedni interfejs FunctionN. Oznacza to, że utworzenie lambdy pociąga za sobą alokację obiektu dla każdej operacji. Aby zmniejszyć narzut, Kotlin obsługuje funkcje inline, które wstawiają ciało higher-order function w miejscu wywołania, eliminując tworzenie anonimowej klasy.

Funkcje jako parametry: przekazywanie zachowania

Przekazywanie funkcji jako argumentu — najczęstszy wzorzec użycia higher-order function. Zamiast tworzyć hierarchię klas z polimorficzną metodą, programista przekazuje potrzebne zachowanie bezpośrednio w miejscu użycia. Realizuje to zasadę „otwartości na rozszerzenia” (Open/Closed Principle) bez dziedziczenia: nowa operacja dodawana jest jako nowa lambda, a nie jako nowa podklasa.

Dla funkcji nullable Kotlin używa typu ((T) -> R)? ze znakiem zapytania po nawiasach. Taką funkcję można wywołać dopiero po sprawdzeniu null lub przez operator ?.invoke(). Sygnatura higher-order function wyraźnie wskazuje, że przekazanie funkcji nie jest obowiązkowe — kod wywołujący może pominąć argument. Jest to przydatne w callbackach i handlerach zdarzeń z opcjonalnym zachowaniem.

kotlin
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]
}

Funkcja-rozszerzenie customFilter przyjmuje parametr predicate typu funkcyjnego (T) -> Boolean. Wewnątrz pętli wywołuje predicate dla każdego elementu i zbiera pasujące. Wywołanie w main przekazuje lambdę { it % 2 == 0 }, gdzie it — niejawna nazwa jedynego parametru lambdy. Dzięki higher-order function logika filtrowania jest całkowicie oddzielona od mechanizmu przeglądania kolekcji.

Funkcje jako wartości zwracane

Higher-order function może zwracać funkcję — taki wzorzec nazywa się fabryką funkcji lub generatorem zachowania. Zwracana funkcja może przechwytywać (closure) zmienne z zewnętrznego zakresu widoczności, zachowując je między wywołaniami. Pozwala to tworzyć konfigurowalne handlery i wyspecjalizowane operacje na podstawie ogólnych szablonów.

Przy zwracaniu funkcji Kotlin wnioskuje zwracany funkcyjny typ ((T) -> R)? z sygnatury. Kompilator sprawdza, czy wszystkie wyrażenia return w ciele zwracają kompatybilne wartości funkcyjne. Przechwycone zmienne są przechowywane w obiekcie lambdy i dostępne tak długo, jak istnieje referencja do niej. Jest to potężny mechanizm, ale wymagający uwagi przy zarządzaniu pamięcią.

kotlin
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
}

Funkcja makeMultiplier przyjmuje factor i zwraca lambdę { x -> x * factor }, gdzie factor jest przechwycony z zewnętrznego zakresu (closure). Przy każdym wywołaniu makeMultiplier tworzona jest nowa funkcja z własną wartością factor. Zmienne double i triple przechowują zwrócone funkcje i mogą być wywoływane wielokrotnie. Ten wzorzec jest szeroko stosowany w konfiguracji klientów HTTP, dekoratorach i middleware.

Higher-order function z lambdami: przykłady

Łączne użycie higher-order function i lambd pozwala budować wyraziste łańcuchy operacji bez zmiennych pośrednich. Standardowa biblioteka Kotlin zawiera dziesiątki higher-order functions: let, run, apply, also, filter, map, flatMap, fold, reduce, forEach, groupBy i inne. Każda z nich przyjmuje lambdę i wykonuje z jej pomocą transformację danych.

kotlin
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) // [ALICJA, KAROL]
}

W przykładzie łańcuch trzech higher-order functions przetwarza listę użytkowników. filter przyjmuje predykat, zostawiając tylko pełnoletnich. map przekształca każdego użytkownika na imię pisane wielkimi literami. sorted sortuje wynik rosnąco. Każda operacja przyjmuje lambdę, a Kotlin zapewnia bezpieczeństwo typowe na wszystkich etapach. Bez higher-order function trzeba by napisać pętlę z if, tymczasowymi listami i sortowaniem ręcznie.

Najczęściej zadawane pytania

Czym różni się higher-order function od zwykłej funkcji?

Higher-order function przyjmuje inną funkcję jako parametr lub ją zwraca. Zwykła funkcja działa tylko z danymi — liczbami, ciągami znaków, obiektami. Higher-order function działa z zachowaniem, przekazując logikę jako argument.

Czy higher-order function może być inline?

Tak, modyfikator inline eliminuje narzut związany z tworzeniem anonimowej klasy dla lambdy. Używając crossinline lub noinline, można zarządzać tym, które lambdy są wstawiane, a które pozostają obiektami.

Jaki jest typ funkcyjny funkcji bez parametrów?

Funkcja bez parametrów i bez wartości zwracanej ma typ () -> Unit. Funkcja z jednym parametrem typu T i zwracająca R zapisywana jest jako (T) -> R. Dla dwóch parametrów — (T, U) -> R i tak dalej aż do 22 argumentów.

Jaka jest różnica między lambdą a funkcją anonimową?

Lambda — to zwięzły zapis { args -> body }, funkcja anonimowa — fun(args): ReturnType { body }. Lambda nie może mieć return bez etykiety, funkcja anonimowa może. Obie mogą być przekazywane do higher-order function.

Kiedy należy unikać higher-order function?

Unikaj higher-order function w gorących pętlach bez inline — każda lambda tworzy obiekt. Dla krytycznej wydajności używaj inline fun. Nie nadużywaj też głębokiego zagnieżdżania lambd — zmniejsza to czytelność.

Podsumowanie

  • Higher-order function — funkcja przyjmująca inną funkcję jako parametr lub zwracająca ją; fundament programowania funkcyjnego w Kotlin
  • Typ funkcyjny (T) -> R deklaruje parametr-funkcję z bezpieczną typowo sygnaturą
  • Wyrażenie lambda — zwarta składnia { args -> body } do przekazywania zachowania
  • Funkcje inline eliminują narzut na tworzenie anonimowych klas dla lambd
  • Fabryki funkcji zwracają funkcję z przechwyconym kontekstem przez mechanizm domknięć
  • Łańcuchy operacji filter-map-sorted budowane są na higher-order functions bez zmiennych pośrednich
  • Bezpieczeństwo typowe higher-order function zapewniane jest przez system typów funkcyjnych Kotlin na etapie kompilacji

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również