From Java to Kotlin - Lambdas

A lambda expression is always surrounded by curly braces

// declaration
{ println("I am a function lambda! ") }

// store in a variable
val printer = { println("I am saved!") }

// invoke a stored lambda
run(printer)

// lambdas with parameters
val printMessage = { message: String -> print(message) }

// invoke it
printMessage("hello there!")

Higher Order Functions

A higher order function is a function that either accepts another function as a parameter, returns a function as its return value, or both

Function Types

This function has two parameters. The first is a string and the second is a function from String to String. The entire function returns Unit (void)

// declare a function which takes a lambda
fun foo(str: String, fn: (String) -> String): Unit {
  val applied = fn(str)
  println(applied)
}

// invoke it
foo("hello", { it.reversed() })

Type Inference

When you use a lambda as a parameter, if there’s only a single parameter, you don’t need to explicitly declare the lambda’s argument type.

If you store a lambda in a variable, there’s no context from which to infer the arg types, so you have to specify them explicitly.

// type inference
{ message -> println(message) }

// no type inference
val getAge = { p: Person -> p.age }
people.maxBy(getAge)

In Kotlin, unlike in Java you’re allowed to access non-final variables and modify them in a lambda.

Member References

You can have a reference to a function that’s declared at the top level and isn’t a member of a class. In this case you omit the class name and start with ::

fun salute() = println("Salute!")
run(::salute) Salute!

// you can store or postpone the action of creating an instance of a class using a constructor reference
data class Person(val name: String, val age: Int)
// constructor reference
val createPerson = ::Person
val p = createPerson("Alice", 29)
println(p)
Extension functions

You can also reference extension functions the same way as a member reference

fun Person.isAdult() = age >= 21
val predicate = Person::isAdult

Returning Functions from Functions

To declare a function that returns another function, you specify a function type as its return type.

This is less used but it’s used when you have a piece of logic in a program that can vary depending on hte state of the program or other conditions.

// declaration
fun bar(): (String) -> String = { str -> str.reversed() }

// invoke
val rev = bar()
rev("hello!")