Jason. Cała informatyka w jednym miejscu!

W ramach postawienia kropki nad i, jeśli chodzi o lambdy w Kotlinie, zdradzę Wam teraz jak działają niektóre funkcje wyższego rzędu w języku Kotlin.

FUNKCJE WYŻSZEGO RZĘDU DZIAŁAJĄ UNIWERSALNIE DZIĘKI LAMBDOM!

Poproszę Was najpierw o przeczytanie co to w ogóle funkcja wyższego rzędu, aby zachować logiczną kolejność czytania żeby potem kumać o co w tym biega. Dopiero wtedy wrócić tu.

Zakładając, że posłuchaliście...

Funkcje jakie mam zamiar przedstawić operują na kolekcjach. Takich jak lista, takich jak zbiór, takich jak mapa. Dzięki wyrażeniom lambda, podstawiamy w jednej linijce kryterium na podstawie CZEGO ma się zrealizować konkretna czynność. Jakie na przykład? Kilka z poniższych.

Dla wszystkich zamieszczonych przykładów, zakładamy że rozmawiamy o następującej liście przechowującej elementy typu "klasa danych »Jewel«":

data class Jewel(val type: String, val price: Int)

val jewels = listOf(Jewel("Szmaragd", 350), Jewel("Diament", 4500), Jewel("Topaz", 420))

MINOFORNULL

"minOfOrNull" to zwrócenie elementu typu kolekcji, które w podanym przez nas kryterium w wyrażeniu lambda (tak działają funkcje wyższego rzędu) zostało uznane za najniżej stojące w hierarchii. W powyższej sytuacji, możemy to interpretować dwojako.

Po podstawieniu "price", klasyfikujemy po wartości:

println(jewels.minOfOrNull { it.price })

A po podstawieniu nazwy, otrzymujemy element którego łańcuch znaków jest ostatni po posortowaniu w kolejności alfabetycznej (litera D "stoi" bliżej niż T i S):

println(jewels.minOfOrNull { it.type })

Jak możecie zauważyć, funkcje wyższego rzędu wymagają tylko prostej lambdy, w której osadzamy interesujące nas kryterium. Możemy pominąć nawiasy, ale tylko w wyjątkowej sytuacji. Pamiętajcie o tym, że metoda uwzględnia napotkanie na wartość "null"! Zatem, zwraca typ akceptujący wartość "null"!

MAXOFORNULL

Sprawa z funkcją "maxOfOrNull" ma się podobnie, z tym że zwraca element uznany przez klasyfikację za wysunięty na pierwszą pozycję. Żeby trzymać się klarowności, dla "price" będzie zwrócony element o największej wartości:

println(jewels.maxOfOrNull { it.price })

a co do nazwy, to "zwycięży" ten łańcuch znaków, który zaczyna się od najdalszej litery (D < S < T):

println(jewels.maxOfOrNull { it.type })

Tak jak u góry, również tutaj może być figa z makiem w przypadku komplikacji, i otrzymać wartość "null"!

SUMOF

Funkcje wyższego rzędu to nie tylko "selekcja najodpowiedniejszego". Używając "sumOf" możecie przyjemnie zsumować wszystkie wartości wskazanej właściwości (liczbowej, oczywiście). Podstawiając do naszego przykładu:

println(jewels.sumOf { it.price })

przekonamy się jaka wychodzi suma wszystkich składników podanej właściwości.

FILTER

Dostępna jest także funkcja filtrująca kolekcję na kształt zapytania w SQL. Wyrażenie lambda w tym przypadku zwraca "Boolean'a" (wartość logiczną) i oznacza ona warunek jaki musi spełnić element, żeby znalazł się na liście zwracanej przez funkcję "filter". Zobaczmy to w akcji:

println(jewels.filter { it.price > 400 })

To zwróci dwa elementy typu "Jewel", które zawierają właściwość "price" większą od czterystu. Jak wspomniałem - czysty "SELECT" w bazach danych!

MAP

Przytoczę także funkcję "map". W wyrażeniu lambda, wstawiamy teraz wyrażenie połączone z właściwością. Dla przykładu, gdybyście mieli listę liczb całkowitych i chcieli każdą z nich przemnożyć przez 10, patrzycie teraz na doskonałego kandydata, który Wam zwróci listę liczb całkowitych, a każda z nich zostanie przemnożona przez dziesięć. A o to przykład dla powyższych danych:

println(jewels.map { it.price*1.5 })

Nie musimy sobie zawracać głowy pętlą "for" i ręcznym przemnażaniem każdej wartości właściwości "price" z osobna. Wystarczy skorzystać z "map".

FOREACH

Funkcje wyższego rzędu to także pętla "for" w charakterze funkcji! Skorzystajcie z "forEach", aby w wyrażeniu lambda zawrzeć instrukcje dla wszystkich elementów jakie mają zostać wykonane. Takie wypisanie na przykład:

jewels.forEach { println(it) }

Strzeżcie się takiego wyjątku, że lambda nie zwraca żadnej wartości (typ "Unit")! Aby przechować jakiekolwiek wyniki, możecie utworzyć sobie zmienną posługując się słowem kluczowym "var" i modyfikować wartość wewnątrz lambdy.

"minOfOrNull" w języku Kotlin - funkcja wyższego rzędu
"maxOfOrNull" w języku Kotlin - funkcja wyższego rzędu

Funkcje wyższego rzędu wymagają podania kryterium w postaci prostego wyrażenia lambda, stając się tym samym elastyczne i dostosowujące się do każdej sytuacji.

Jak widzicie, jakiej funkcji nie użyjecie, wszystkie kręcą się wokół wyrażenia lambda. To one otwierają wrota do uniwersalnego definiowania kryterium, dzięki czemu funkcja jest jedna, a możliwości nieskończona ilość. Pokazując to na przykładzie listy obiektów, widać cały potencjał tych funkcji kiedy nie da się ustalić domyślnego kryterium (pamiętacie zabawę z "compareTo"?).


Tych funkcji wyższego rzędu jest o wiele więcej. Dla tych, którzy pragną poznać je wszystkie, kieruję do dokumentacji Kotlina.

PODOBNE ARTYKUŁY