Kotlin for Seniors: Code Less, Solve More. 3 tips. Part 2.
Kotlin is all about writing less code and solving more problems. If you’re a seasoned developer, you already know the power of clean, efficient code.
Here are three pro tips that will help you write cleaner, more expressive Kotlin code with less boilerplate and better performance. 🚀
1. Master inline
and crossinline
for performance
Lambda functions are powerful but come with a hidden cost — they create objects and add function call overhead. Kotlin’s inline
keyword helps eliminate this by replacing the function call with its actual code at compile time.
Using inline
for performance
❌ Without inline
(creates extra objects)
fun execute(task: () -> Unit) {
task()
}
✅ With inline
(no extra objects, better performance)
inline fun execute(task: () -> Unit) {
task()
}
Here, execute()
is replaced directly in the bytecode, avoiding object creation and function calls.
When to use crossinline
?
Sometimes, you need an inline
function but don’t want to allow early return from the lambda. That’s where crossinline
comes in:
inline fun runTask(crossinline action: () -> Unit) {
Thread {
action() // `crossinline` ensures action() is not returned early
}.start()
}
Use crossinline
when the lambda is executed inside another function (like a background thread) and cannot return from the outer function.
✅ Rule of Thumb: Use inline
for performance and crossinline
when passing lambdas inside other functions.
2. Simplify complex names with typealias
If your team struggles with long generic types, typealias
can make your code much more readable.
❌Without typealias
(ugly, hard to read)
val cache: HashMap<String, List<Pair<Int, String>>> = hashMapOf()
Not great, right? Let’s simplify it:
✅ Using typealias
for clarity
typealias UserCache = HashMap<String, List<Pair<Int, String>>>
val cache: UserCache = hashMapOf()
Another great use case is simplifying callback functions:
typealias CompletionHandler = (Boolean, String) -> Unit
fun fetchData(callback: CompletionHandler) {
callback(true, "Success!")
}
When to use typealias
?
✔️ When your types are too long
✔️ When defining complex function types
✔️ When improving code readability
3. Write less boilerplate with delegated properties
Kotlin’s delegated properties (by lazy
, by Delegates.observable
, by map
) help eliminate boilerplate code when managing object properties.
lazy
for on-demand initialization
Instead of initializing a variable immediately, use lazy
to initialize it only when needed:
val expensiveData: String by lazy {
println("Loading data...") // Runs only once
"Expensive Data"
}
fun main() {
println(expensiveData) // First call triggers loading
println(expensiveData) // Second call reuses existing data
}
✅ Best Use Case: Large objects that don’t need immediate loading (e.g., database connections, configuration settings).
Observable
for property change listeners
Need to track property changes? Use observable
:
import kotlin.properties.Delegates
var theme: String by Delegates.observable("Light") { _, old, new ->
println("Theme changed from $old to $new")
}
fun main() {
theme = "Dark"
theme = "Blue"
}
Conclusion
Kotlin offers powerful tools to help you write less code and solve more problems efficiently.
What are your favorite Kotlin tricks? Let’s discuss in the comments! 👇