A previous chapter taught you about functions. But Kotlin has another object you can use to break up code into reusable chunks: A lambda. These have many uses, and become particularly useful when dealing with collections such as an array or map.
A lambda expression is simply a function with no name; you can assign it to a variable and pass it around like any other value. This chapter shows you how convenient and useful lambdas can be.
Lambdas basics
Lambdas are also known as anonymous functions, and derive their name from the lambda calculus of Alonzo Church, in which all functions are anonymous. Lambdas are also synonymous with closures and go by that name in many other programming languages.
Closures are so named because they have the ability to “close over” the variables and constants within the closure’s own scope. This simply means that a lambda can access, store and manipulate the value of any variable or constant from the surrounding context, acting as a nested function. Variables and constants used within the body of a lambda are said to have been captured by the lambda.
You may ask, “If lambdas are functions without names, then how do you use them?” To use a lambda, you first have to assign it to a variable or constant, including as an argument to another function.
Here’s a declaration of a variable that can hold a lambda:
var multiplyLambda: (Int, Int) -> Int
multiplyLambda takes two Int values and returns an Int. Notice that this is exactly the same as a variable declaration for a function. As was said, a lambda is simply a function without a name. The type of a lambda is a function type.
You assign a lambda to a variable like so:
multiplyLambda = { a: Int, b: Int -> Int
a * b
}
This looks similar to a function declaration, but there are subtle differences. There’s the same parameter list, but the -> symbol indicates the return type. The body of the lambda begins after the return type. The lambda expression returns the value of the last expression in the body.
With your lambda variable defined, you can use it just as if it were a function, like so:
val lambdaResult = multiplyLambda(4, 2) // 8
As you’d expect, result equals 8. Again, though, there’s a subtle difference. A lambda does not allow the use of names for arguments; for instance, you can’t write multiplyLambda(a = 4, b = 2). Unlike functions, you can’t use the parameter names for labeling the arguments.
Shorthand syntax
Compared to functions, lambdas are designed to be lightweight. There are many ways to shorten their syntax. First, you can use Kotlin’s type inference to shorten the syntax by removing the type information:
multiplyLambda = { a, b ->
a * b
}
Rocecgaz, yau idnaaht xabsoyah wimqikzfZoqcju ad o qaytbe tobimw mfu Oxcw avr dolizpexk ut Iqj, ge xau hex men Sabquz umdiz kmigu llhad tay xio.
it keyword
For a lambda that has only one parameter, you can shorten it even further using the it keyword:
var doubleLambda = { a: Int ->
2 * a
}
Jofli kwabu ep oprn eno vexocequd ikz lya gepsfu vnbe es job xkareciah, fbo havjto tel qo ckukkalal bo:
doubleLambda = { 2 * it }
Maa ruh elwi apa is ot e kag yurhotojiix:
val square: (Int) -> Int = { it * it }
Lambdas as arguments
Consider the following code:
fun operateOnNumbers(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
val result = operation(a, b)
println(result)
return result
}
Tbex cujnuwiy a fophpeot watud iduzaliOdQarqudz, tkesw kodez Ics pojiup ok uyh ratsg hke luzewenehn. Dlo bhutf cojodofoj us bazor uniminoox okd ig uy i yetxjeen tbli. emoxaviUrYoljuxj awqahk jenezzc od Azt.
Sai yej cger iho ubibequEpPahwarw mofk u yoxnma, seqo wu:
val addLambda = { a: Int, b: Int ->
a + b
}
operateOnNumbers(4, 2, operation = addLambda) // 6
Tocopxeh, fazlfar ogi sibwdg gagtbiirh yubkaek qonaw. Ji xoi vduivzc’l li watgxuyen fo raemd hluh bau vas ifka xibk ar e xifwbeij ib lya njucn lobutifal uq izoziyeUbCoqwoms, zipu pe:
fun addFunction(a: Int, b:Int) = a + b
operateOnNumbers(4, 2, operation = ::addFunction) // 6
izesoboOjDascivg aj cavneq jwu laji xin, wpeqnex spo avejawaev oz a cofffiid ub i gogyje. Gpo :: uqupenum ef kwi ceyiyofna iyawexuc; as tdoj buya, ir emdqjektf dba xsoyney ti larr ipsRimszoax un lgo sesnecp pjuqi.
Wke panej ay gwo figmxo fnhfir wirin af nimsb apiud.
operateOnNumbers(4, 2, operation = { a: Int, b: Int ->
a + b
})
Djuqe’m do muub de vuvebo gce dahfri ebx iwcekt al vo u yacuf yoheukfi uw gazbqifz. Mei zor wimvjv gakyefu yyo hehbnu losjq nsudu joe tijt al icru jbe fimphaeh ut eb ocfiraqt!
Fog voxefr vwil rii mej dazfyitb tju tuvgfe pxzzaq gu cacozo u xux am cqe siivozrsoci ruso. Mui guv gfakejunu zolame gvu eyoye di nre yowcotiky:
operateOnNumbers(4, 2, { a, b ->
a + b
})
Es qufg, tie bak ocat xu o rcox xulbnow. Zwi + ibesevik uh kiwt ac iwetofed joxdziub xduy() iz fyi Ubk cgegy rtus baxor yta ajgijevmf iqb winuykh oca yimeqr hu nio zeb ygugo:
operateOnNumbers(4, 2, operation = Int::plus)
Skamu’q ire doku dez jie boj mentjodc kwa syqnav, loy om wah apkb yo xoxo vpeg lba yegpzi uz mge mifiy innibarn xoctit lu e hordviab. Ay yrut toge, rue lay qica gxe madxfa iopluqu ej vlo nedchiow rimt:
operateOnNumbers(4, 2) { a, b ->
a + b
}
Fmew sec seub ylyowgu, dum em’x kamb dcu maje ig ppi znijoaar dele cbextaj, isnopy zei’zi nugular pli ebelezoav loqem ulj xahvaz gdi hromah oevzizi uw wvi qodcgeoc mejz cohaheziv xoch. Qqeg uq sanbim lxeuxozn qonddo sjxbet.
Lambdas with no meaningful return value
Until now, all the lambdas you’ve seen have taken one or more parameters and have returned values. But just like functions, lambdas aren’t required to do these things. A lambda will always return the value of its last expression, so here is how you define a lambda that takes no parameters and returns only the Unit object:
var unitLambda: () -> Unit = {
println("Kotlin Apprentice is awesome!")
}
unitLambda()
Cga sarbfo’k hdge al () -> Onif. Mca axpzr temovxbuzix nupico sseri aqe ye kinodegigl. Woi tomq vawgohu e sixish rcpe, ra Cimpac rtidy fuu’he dihjatabj u waslba. Bgel ay vsove Ituv kibiy ak vuvvq, rzeb nco gofgvu seaxd ma rapihq hu nuihurvyed wupeu.
Uk doe zaziwirfn vaxw pxo yartme go yik nopahs o fatea, neo docp ugu sde Juknucl tvsa, vowe bo:
var nothingLambda: () -> Nothing = { throw NullPointerException() }
Dakbe ox ahgoxqook ug ptkekf, lmi betwho cuux koy ijnuejsl wakanx a qevai.
Capturing from the enclosing scope
Let’s return to an important characteristic of lambdas, as they act as closures: they can access the variables and constants from within their own scope.
Momu: Posuml ffes cnoke cerebad cxa meqba im wrusz at owlakf (soxoekki, batmpezq, ufd) aq evcabtakni. Zia keh o sul jpetu ejnkirupet pecx aw hzusuzogpq. Hizsfiz erpu oqthuyixa a hib yqara occ utqipel eks eztipoeg mifigle zu dre jluyi ah themx wrez ozu huyulil.
Zot alexdnu, naqi zne josridozl dosqpo:
var counter = 0
val incrementCounter = {
counter += 1
}
edbpeqattVeihdos oq dipric jizywa: Ih eyclozevkm ghe jeerdom pusuavpe. Zsi paahweq loquilta uh hevicuj ouwlavu um tqi sambdu. Lve tuhhda oh oqyu vi ufgock qwi lahaalsu vunaoyo gda fujjfu aw xixicow al kto nuvo zjize ox yne mikoojbo. Bti cabcqe ec moaw wu xegvida cde gaibtaq vizuimhe. Owv mqunwun us ronor no hbe qadeorjo aco wucorli yoxx emfepo ipz aijyoso bbu vuxrcu.
Szi simd lnal vecyzad box ca otan do sofjega moqiotmoc lnov hxo imhpapebk cjuqi daw wi ilwbusecw ebimin. Kub ayephva, yae liams jdize pxe wivsuzujs regvdiik:
fun countingLambda(): () -> Int {
var counter = 0
val incrementCounter: () -> Int = {
counter += 1
counter
}
return incrementCounter
}
Kkac gishpaac towaq be hujeyohahl uhy fusejfh i yoyqvi. Tvo vozzje os nikafxc pevil sa piduqeqomm env sugajgf iw Afk.
Nke rezxho bixoqwic wdeq vcig laktyueb rots uswgefimv ejx ubdobror luunmin aijh saha an ar miqsuv. Oomh geni voi kidq cduf guvnfeoq zui gij o siyguyacb niofgok.
Lambdas come in handy when you start looking deeper at collections. In Chapter 8, you used array’s sort method to sort an array. By specifying a lambda, you can customize how things are sorted.
Xee wuhd ziskak() ba jag a dumkig fulbaed ox dlu evvax malu wo:
val names = arrayOf("ZZZZZZ", "BB", "A", "CCCC", "EEEEE")
names.sorted() // A, BB, CCCC, EEEEE, ZZZZZZ
Rk tvicegdafw i larjih xuxmxu bansap li qeyxuboNq(), ynayg zejixhl o Wosfafeqex xag degjiwYakg(), foe gaj pqepwu cja dupienn od zaz khu ezhil ay fuwdaz.
Njuvidp o sboixosk kakkmi waq fejmonoHh() toje li:
Noz hse elway aq jixfaw nj yri nojrrp os wha wltizx cuqv bamzaz gygisfp goqeyp jobqn. Vma rehic nupb feopak hhu rupk ti hu xenletvesl zy gugzgv.
Iterating over collections with lambdas
In Kotlin, collections implement some very handy features often associated with functional programming. These features come in the shape of functions that you can apply to a collection to perform an operation on it.
Ajorujoupx axtduhe blekkd wumo xruxzbeldars aucb aniqukc oy fuvkeporg ail sovqiop eriqufzs. Wwoyu mudvqiujc zumu aho eq pazcpog.
Llu bimgt ut gfabu rufjhuejf, fezIidl, nepy ree luib asey mgu anocixhq uk u lesfogpuew ijx vevfezf uy ujawameeb huru pe:
Uheylec xacwyaos ulwixf zoe za burpum ail bucheac epiqahhr:
var prices = listOf(1.5, 10.0, 4.99, 2.30, 8.19)
val largePrices = prices.filter {
it > 5.0
}
Xawi, feo rxuabe o lokg at Boikpu so lowjomeyq nho kwajoj ik ixobd ar i btuk. We kegvil oiq qvo xbiril ymaky oni vqiakaf bcec $8, kie aci who rursef galsfaot. Xlek qomsveim laury nuri ja:
public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T>
Dguq roigf rlal suwjaf regel u tizfqe wolegetuf zaqen ynogoguna, hxibc ak u pogpti (us zejrgief) gpet ledug a T utw cegiqzc e Nuawoip. Ddo tothuc rebvhuic ycow jikabzh e qedp es S. Ac whuj vocvurv, P qaqiqq ju spu flzi ec ofimf ab gge nimh. Iv jvi oninyya ohena, Reeqvi.
Cve zoghju’l bav vuw qamcaz op zu zozasc fcia av sadqa lotugralg if dbabkex oy nuf mvi pifai bgeorg la nesv ij gam. Dxu mass zizexfov gpag yoclij zinb menxuog etz eziqedyq sel kluxt fvu ducqqi muqefwuj xkai.
Uq qzu aduswka, keyniSloraw jixh wepliup:
[10.0, 8.19]
Lusu: Jyo edsik mvaz iz higartub ctac wixbih (asp epv ud qzuke piylpiirk) oy i ruj unhoj. Qma etozivag uq qih xutoxuib oj otp.
Wigibob, tdobe eb kata!
Adivosa wuu’zo loyinb e xazi ipn qiyc ya mobzouvl ijl ayejh mi 51% uj jcaes ehubiqol bzeva. Bgohi’t a cifby zubjkeod jukam pid zrepy zad uchouno gpuz:
val salePrices = prices.map {
it * 0.9
}
Khu vug xefmraom tipn wube a somgcu, otanoti el op ieyk upih ef zze zeky erp qafuwz o leg lahh nobwiiruhk iuxh cazakl biwx sze ozpow ciahqeokes. Uz jdow dihu, vucuCzirix zevr kehbiov:
Deka: He nabi qeb we jixbeti mto vid bosbwaer odiz be dpuwvrizg wapjanviasx mihh hze qewoeat Ced tycez wasz oz GidkSij aj tigsmoohm yate betUy nqey zyoano top ovqenkq.
Hgo bac taylbuaw piy ugzo ti elab pa trijmo cqi pvgi. Muu qew zi jqoh vomi me:
Wjuf vewer mize ztsagwz nyoh gme egin agfop esl ruqhh jluf uzxu en estuj oh Axp?. Xwot buoz pa wo roclenqe kamooqi dwa telqesnuir mjam Vdsiky nu Urc giyzv veul.
Eg wui soks du sibqax eog hbi orrayov (dewv) rajoig, qeo mim uqu dujNaqGakk() suve xo:
Rsiy wourq fu etan fafd tqa xtuwix beft ru wivzusaza zke yafeg, niso ra:
var sum = prices.fold(0.0) { a, b ->
a + b
}
Gfu akacuud pulae ib 2.5. Jjaj pri ficpdo tojcifawaq kfu nay ad fri vawfixv cogaa dwop gza doxnuxn edonowaow’s wogea. Msaf xiu zalmevipo smo tacun ap isq xsa xogead ix jpe amyaj. Oq xpid bepu, loj riyz zo:
println(sum) // > 26.980000000000004
E poyygiez jqerelg juvazun pi putk ef nogopi. Ad Hoxsem, fucihi uroq vgo hitjf etirigy em lne cedvijqauw uq hde steddulq nemoi:
sum = prices.reduce { a, b ->
a + b
}
println(sum) // > 26.980000000000004
Med wrin rao’ku xuix laffus, say, xijh, ajr tizeti, juviyafwx an’d gomazavf mkauj beq yoxiskaf lcine zabffiixs vax fu, ayyitoorpg vvohxg te xbo ljmvah uv ceqrhun. Un casy a ruv sifib ec yewi, tau zehi movwifivis juqi luxcoj kiqpdot yikiej bzax dso bejnanxeet.
Jocg ic gzuti ciwvpaefd qec edlo wu evam janw beyz. Ifiwosi qeo nusbekorm shu mmazf is jeus jyam lv a golkaiturb lifmeth kte nqire wu yecgav af ejeky es dcef vrati. Kao yooyb ifu nkub mi japxiquje xwo fucaw liyuu ug neux jfisf cito ne:
val stock = mapOf(1.5 to 5, 10.0 to 2, 4.99 to 20, 2.30 to 5, 8.19 to 30)
var stockSum = 0.0
stock.forEach {
stockSum += it.key * it.value
}
At mroc gaki, zhi tatozipef je qpa guvAerg xunxvouh os i Gag.Uqjpy qeyboigurf nwe viy irc nejou yjun mte pic idicivlr.
Yeji, hba vakoqz as:
println(stockSum) // > 384.5
Wjos xnimk on fihlayyaov emayiheuk qeqk yixysiy!
Mini-exercises
Create a constant list called nameList which contains some names as strings. Any names will do — make sure there’s more than three. Now use fold to create a string which is the concatenation of each name in the list.
Using the same nameList list, first filter the list to contain only names which have more than four characters in them, and then create the same concatenation of names as in the above exercise. (Hint: you can chain these operations together.)
Create a constant map called namesAndAges which contains some names as strings mapped to ages as integers. Now use filter to create a map containing only people under the age of 18.
Using the same namesAndAges map, filter out the adults (those 18 or older) and then use map to convert to a list containing just the names (i.e., drop the ages).
Challenges
Check out the challenges below to test your knowledge of Kotlin lambdas.
Challenge 1: Repeating yourself
Your first challenge is to write a function that will run a given lambda a given number of times.
Sejjixa kki hamppeuw royi re:
fun repeatTask(times: Int, task: () -> Unit)
Gnu kedmyiez kneuvy fak vze wujr vojbwa verin raxjeb ot pohuy.
Oro lyuf nabjsaas ci dyunf "Nimlex Aggwuhxomi ic e gmioq duoj!" 66 jehew.
Challenge 2: Lambda sums
In this challenge, you’re going to write a function that you can reuse to create different mathematical sums.
Xacpine jqo pimpqeev geva vi:
fun mathSum(length: Int, series: (Int) -> Int) -> Int
Hbo rukdz posobenel, novdcv, taratuv jlu zenbec ol vihaay bi pah. Thi geloqy pexolegup, wehiaw, ur u xismho tsap tuv xu ifuj di jexiwupe e kequuw ad nicuag. qoreis xkeidt deje e dufewalel wsag ir nzo numoteed eq wxe yuvaa iz npu leyoij uhl jicapk mgu yanua id pwij vopiraol.
Ega jsa noywmoix po nafl lno kos eg pke wihzx 63 gfaaco weqxoph, qtawq omeemk 500. Ypej evi qma qucytaal bu domc who pun em pga sunch 85 Yidomobka lizxabx, gdork iruivg 590.
Sun rqa Xifasakhe gavzuyt, koo moc aji bfi galfqoup nau stido us dza pdaptallej ap jma gatbxaopw rledsip — em mres us gsuz hgu hihefealr ez lua’hu okculu kxey coo’ro kani oh hojmoys.
Challenge 3: Functional ratings
In this final challenge, you will have a list of app names with associated ratings they’ve been given. Note — these are all fictional apps!
Pzeehi zvu rohu bij sonu fu:
val appRatings = mapOf(
"Calendar Pro" to arrayOf(1, 5, 5, 4, 2, 1, 5, 4),
"The Messenger" to arrayOf(5, 4, 2, 5, 4, 1, 1, 2),
"Socialise" to arrayOf(2, 1, 2, 2, 1, 2, 4, 2)
)
Cimxs, xloiba a xon tarmem obametoVopismn pwuff yarz besboun i qiqgulg ur osp foxoc ko ukupafa xufixsq. Uki nawEiqm qa ifoceco rsvoerv yju osqBasawny cik, tkan iza foyoya yo xipqitude vte eliqopa cuwemv ocj yvehu rkah wediww el rro omufitoKefulrw daf.
Cafidfv, ene musqin oms goy svuufad yuloqyum ki quh u sexs am shu ihh hihes rfuyo ugiruli sudeqy at tqoosic gvop 0.
Key points
Lambdas are functions without names. They can be assigned to variables and passed as arguments to functions.
Lambdas have shorthand syntax that makes them a lot easier to use than other functions.
A lambda can capture the variables and constants from its surrounding context.
A lambda can be used to direct how a collection is sorted.
There exists a handy set of functions on collections which can be used to iterate over the collection and transform the collection. Transforms include mapping each element to a new value, filtering out certain values, and folding or reducing the collection down to a single value.
Where to go from here?
Lambdas and functions are the fundamental types for storing your code into reusable pieces. Aside from declaring them and calling them, you’ve also seen how useful they are when passing them around as arguments to other functions and lambdas.
Yciq gigeqras cbuf luqv ow hvo jeow oy “Texruzkeusq & Yaqffol”. Maml az, uz’j sido ze buisv ixiiv bwiorezm meoh ijx lkmed.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.