
This is a chapter from the book Functional Kotlin. You can find it on LeanPub or Amazon. It is also available as a course.
An expression used to create an object representing a function is called a function literal, so both lambda expressions and anonymous functions are function literals.
fun main() { val f: () -> Unit = {} f() // or f.invoke() }
main function print?fun main() { { println("AAA") } }
produce function return?fun produce() = { 42 } fun main() { println(produce()) // ??? }
42. Braces are not a part of single-expression function notation. The produce function returns a lambda expression of type () -> Int, so the above code on JVM should print something like Function0<java.lang.Integer>, or just () -> Int. To fix this code, we should either call the produced function or remove the braces inside the single-expression function definition.fun produceFun() = { 42 } fun produceNum() = 42 fun main() { val f = produceFun() println(f()) // 42 println(produceFun()()) // 42 println(produceFun().invoke()) // 42 println(produceNum()) // 42 }
->. Before the arrow, we specify parameter names and types, separated by commas. After the arrow, we specify the function body.fun main() { val printTimes = { text: String, times: Int -> for (i in 1..times) { print(text) } } // the type is (text: String, times: Int) -> Unit printTimes("Na", 7) // NaNaNaNaNaNaNa printTimes.invoke("Batman", 2) // BatmanBatman }
fun setOnClickListener(listener: (View, Click) -> Unit) {} fun main() { setOnClickListener({ view, click -> println("Clicked") }) }
_) instead of its name. This is a placeholder that shows that this parameter is ignored.setOnClickListener({ _, _ -> println("Clicked") })

data class User(val name: String, val surname: String) data class Element(val id: Int, val type: String) fun setOnClickListener(listener: (User, Element) -> Unit) {} fun main() { setOnClickListener({ (name, surname), (id, type) -> println( "User $name $surname clicked " + "element $id of type $type" ) }) }
inline fun <R> run(block: () -> R): R = block() inline fun repeat(times: Int, block: (Int) -> Unit) { for (i in 0 until times) { block(i) } } fun main() { run({ println("A") }) // A run() { println("A") } // A run { println("A") } // A repeat(2, { print("B") }) // BB println() repeat(2) { print("B") } // BB }
In the example above, bothrunandrepeatare simplified functions from the standard library.
setOnClickListener in the following way:setOnClickListener { _, _ -> println("Clicked") }
sum and product from the introduction? We have implemented them using the fold function with a trailing lambda.fun sum(a: Int, b: Int) = (a..b).fold(0) { acc, i -> acc + i } fun product(a: Int, b: Int) = (a..b).fold(1) { acc, i -> acc * i }
fun call(before: () -> Unit = {}, after: () -> Unit = {}) { before() print("A") after() } fun main() { call({ print("C") }) call { print("B") } }
fun main() { call(before = { print("C") }) call(after = { print("B") }) }
return, the result of the last statement is returned. For example, { 42 } returns 42 because this number is the last statement. { 1; 2 } returns 2. { 1; 2; 3 } returns 3.fun main() { val f = { 10 20 30 } println(f()) // 30 }
return will not help (for reasons we will cover later).fun main() { onUserChanged { user -> if (user == null) return // compilation error cheerUser(user) } }
return in the middle of a lambda expression, we need to use a label that marks this lambda expression. We specify a label before a lambda expression by using the label name followed by @. Then, we can return from this lambda expression calling return on the defined label.fun main() { onUserChanged someLabel@{ user -> if (user == null) return@someLabel cheerUser(user) } }
onUserChanged label in the example above.fun main() { onUserChanged { user -> if (user == null) return@onUserChanged cheerUser(user) } }
fun main() { val magicSquare = listOf( listOf(2, 7, 6), listOf(9, 5, 1), listOf(4, 3, 8), ) magicSquare.forEach line@ { line -> var sum = 0 line.forEach { elem -> sum += elem if (sum == 15) { return@line } } print("Line $line not correct") } }
import kotlin.* fun main() { val cheer: () -> Unit = { println("Hello") } cheer.invoke() // Hello cheer() // Hello val printNumber: (Int) -> Unit = { i: Int -> println(i) } printNumber.invoke(10) // 10 printNumber(20) // 20 val log: (String, String) -> Unit = { ctx: String, message: String -> println("[$ctx] $message") } log.invoke("UserService", "Name changed") // [UserService] Name changed log("UserService", "Surname changed") // [UserService] Surname changed data class User(val id: Int) val makeAdmin: () -> User = { User(id = 0) } println(makeAdmin()) // User(id=0) val add: (String, String) -> String = { s1: String, s2: String -> s1 + s2 } println(add.invoke("A", "B")) // AB println(add("C", "D")) // CD data class Name(val name: String) val toName: (String) -> Name = { name: String -> Name(name) } val name: Name = toName("Cookie") println(name) // Name(name=Cookie) }
val cheer = { println("Hello") } val printNumber = { i: Int -> println(i) } val log = { ctx: String, message: String -> println("[$ctx] $message") } val makeAdmin = { User(id = 0) } val add = { s1: String, s2: String -> s1 + s2 } val toName = { name: String -> Name(name) }
val printNumber: (Int) -> Unit = { i -> println(i) } val log: (String, String) -> Unit = { ctx, message -> println("[$ctx] $message") } val add: (String, String) -> String = { s1, s2 -> s1 + s2 } val toName: (String) -> Name = { name -> Name(name) }
it keyword instead of specifying its name. Since the type of it cannot be specified explicitly, it needs to be inferred. Despite this, it is still a very popular feature.val printNumber: (Int) -> Unit = { println(it) } val toName: (String) -> Name = { Name(it) } // Real-life example, functions will be explained later val newsItemAdapters = news .filter { it.visible } .sortedByDescending { it.publishedAt } .map { it.toNewsItemAdapter() }
fun makeCounter(): () -> Int { var i = 0 return { i++ } } fun main() { val counter1 = makeCounter() val counter2 = makeCounter() println(counter1()) // 0 println(counter1()) // 1 println(counter2()) // 0 println(counter1()) // 2 println(counter1()) // 3 println(counter2()) // 1 }
i, is called a closure.processor variable below, which is defined using both approaches.val processor = label@{ data: String -> if (data.isEmpty()) { return@label null } data.uppercase() } val processor = fun(data: String): String? { if (data.isEmpty()) { return null } return data.uppercase() }
return keyword. To use return we need to have a label.return and must specify the result type.[^04_2]: Best practices regarding naming arguments are explained in Effective Kotlin, Item 17: Consider naming arguments. The named argument convention is explained in Kotlin Essentials, Functions chapter.
[^04_3]: Also, the above algorithm is poorly implemented. It should instead use
sumOf function, which we will present later in this book.