Kotlin Lambda Basics
Introduction
Lambda expressions (or simply "lambdas") are one of the most powerful features in Kotlin. They allow you to write concise code by defining anonymous functions that can be passed as arguments, stored in variables, or returned from other functions. If you're coming from Java, think of lambdas as a more elegant way to implement interfaces with a single method.
In this tutorial, we'll explore the basics of Kotlin lambdas, understand their syntax, and see how they can make your code more readable and maintainable.
What is a Lambda Expression?
A lambda expression is essentially a function without a name (anonymous function) that can be used as an expression. In Kotlin, lambdas are enclosed in curly braces { }
.
Here's the general syntax of a lambda expression in Kotlin:
{ parameter1: Type1, parameter2: Type2 -> body_of_lambda }
The parameters and their types are declared before the arrow ->
, and the body of the lambda follows after it.
Basic Lambda Syntax
Let's start with a simple lambda example:
val sum = { a: Int, b: Int -> a + b }
In this example:
- We've created a lambda that takes two
Int
parameters and returns their sum - The lambda is assigned to a variable named
sum
- We can now use
sum
as a function
To invoke this lambda, we call it like a regular function:
val result = sum(5, 3)
println(result) // Output: 8
Type Inference with Lambdas
Kotlin's type inference works with lambdas too. When the compiler can determine the parameter types from context, you can omit them:
// Lambda with explicit parameter types
val multiply: (Int, Int) -> Int = { a: Int, b: Int -> a * b }
// Lambda with type inference - parameter types are omitted
val multiply: (Int, Int) -> Int = { a, b -> a * b }
In both cases, multiply
is a lambda that accepts two integers and returns their product.
Lambda as the Last Parameter
When a function's last parameter is a lambda, you can pass it outside the parentheses:
fun performOperation(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
// Regular way to call
val result1 = performOperation(5, 3, { a, b -> a + b })
// Using the trailing lambda syntax
val result2 = performOperation(5, 3) { a, b -> a + b }
Both calls do the same thing, but the trailing lambda syntax is more readable and is a common pattern in Kotlin.
it: Implicit Name for Single Parameter
If your lambda has only one parameter, you can omit the parameter declaration and use it
as the implicit name:
val numbers = listOf(1, 2, 3, 4, 5)
// Using explicit parameter
numbers.filter({ number -> number > 3 })
// Using the implicit 'it' parameter
numbers.filter { it > 3 }
The result in both cases is [4, 5]
. The second version is more concise and very common in Kotlin code.
Real-world Examples
Example 1: Filtering a List
One of the most common uses of lambdas is with collection operations:
val fruits = listOf("apple", "banana", "cherry", "date", "elderberry")
// Filter fruits that start with 'a'
val aFruits = fruits.filter { it.startsWith('a') }
println(aFruits) // Output: [apple]
// Filter fruits with length > 5
val longFruits = fruits.filter { it.length > 5 }
println(longFruits) // Output: [banana, cherry, elderberry]
Example 2: Button Click Listener (Android)
In Android development, lambdas are frequently used for event handling:
// Traditional anonymous class (Java style)
button.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
// handle click
toast("Button clicked!")
}
})
// Same thing with Kotlin lambda
button.setOnClickListener {
toast("Button clicked!")
}
The lambda version is much more concise and readable.
Example 3: Custom Sorting with lambdas
data class Person(val name: String, val age: Int)
val people = listOf(
Person("Alice", 29),
Person("Bob", 31),
Person("Charlie", 25)
)
// Sort by age
val sortedByAge = people.sortedBy { it.age }
println(sortedByAge)
// Output: [Person(name=Charlie, age=25), Person(name=Alice, age=29), Person(name=Bob, age=31)]
// Sort by name length
val sortedByNameLength = people.sortedBy { it.name.length }
println(sortedByNameLength)
// Output: [Person(name=Bob, age=31), Person(name=Alice, age=29), Person(name=Charlie, age=25)]
Lambda with Receiver
Kotlin also supports lambdas with receivers, where the lambda has access to the methods and properties of a specified object without qualifier. This is a more advanced topic, but here's a simple example:
val greet: String.() -> String = { "Hello, $this!" }
val greeting = "World".greet()
println(greeting) // Output: Hello, World!
In this example, String.()
means that within the lambda, this
refers to a String instance.
Summary
In this tutorial, we've covered the basics of Kotlin lambdas:
- Lambda expressions are anonymous functions that can be passed around as values
- The basic syntax is
{ parameters -> body }
- Type inference allows for more concise code
- For single-parameter lambdas, you can use
it
instead of naming the parameter - Trailing lambda syntax makes code more readable when a lambda is the last parameter
- Lambdas are commonly used with collections, for event handling, and in many other scenarios
Lambdas are a cornerstone of functional programming in Kotlin and mastering them will greatly improve your code quality and expressiveness.
Exercises
To practice your understanding of lambdas, try these exercises:
- Write a lambda that returns the square of a number, then use it to transform a list of integers.
- Create a function that takes a name and a lambda, then calls the lambda with the name as an argument.
- Use the
filter
andmap
functions with lambdas to find all even numbers in a list and multiply them by 3. - Write a lambda with receiver that adds a prefix to a string.
Additional Resources
- Kotlin Official Documentation on Lambdas
- Functional Programming with Kotlin
- Higher-Order Functions and Lambdas
Happy coding with Kotlin lambdas!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)