Top mistakes of beginner Kotlin developers
Kotlin is a modern, concise, and safe language that is rapidly gaining popularity, especially in Android development. However, its syntax, which incorporates the best of Java and functional languages, often confuses beginners. Many come from the world of Java or Python and make typical mistakes that negate Kotlin's advantages. In this article, we will analyze the 4 most common mistakes of beginner developers, show how to fix them with code examples, and give practical advice.
1. Ignoring Null Safety and incorrect use of operators
Null Safety is Kotlin's main feature. But beginners often either completely avoid nullable types or overuse the !! operator, turning the code into Java with NPE.
Mistake: Excessive use of !!
fun getUserName(user: User?): String { return user!!.name // If user == null — NPE}How to do it correctly:
fun getUserName(user: User?): String { return user?.name ?: "Guest" // Safe call with Elvis operator}Tip: Use ?.let, ?: or requireNotNull for explicit null handling. The !! operator is only justified in tests or when you are absolutely sure of the value.
2. Confusion between mutable and immutable collections
Kotlin clearly separates MutableList and List. Beginners often declare everything with var and mutableListOf, which leads to side effects.
Mistake: Modifying a list inside a function
fun processItems(items: MutableList<String>) { items.add("new") // Modifies the original list}How to do it correctly:
fun processItems(items: List<String>): List<String> { return items + "new" // Returns a new copy}Tip: By default, use immutable collections (listOf, mapOf). Use mutable versions only inside local functions or classes.
3. Incorrect use of Sealed classes and when
Sealed classes are a powerful tool for modeling restricted hierarchies. But beginners forget that when must be exhaustive.
Mistake: Incomplete when
sealed class Result { data class Success(val data: String) : Result() data class Error(val message: String) : Result()}
fun handle(result: Result) { when (result) { is Result.Success -> println(result.data) // Forgot about Error — the code will compile, but there will be a warning }}How to do it correctly:
fun handle(result: Result) { when (result) { is Result.Success -> println(result.data) is Result.Error -> println(result.message) } // Now when is exhaustive}Tip: Always add else or handle all branches. Use when as an expression so the compiler checks for completeness.
4. Overusing lambdas and confusion with higher-order functions
Kotlin encourages a functional style, but inexperienced developers often write unreadable chains or confuse it with named parameters.
Mistake: Overly complex chain
list.filter { it > 0 }.map { it * 2 }.forEach { println(it) }How to do it correctly (with named parameters):
list.filter { number -> number > 0 } .map { number -> number * 2 } .forEach { number -> println(number) }Tip: For short lambdas, use it; for complex ones, use explicit names. Break long chains into intermediate variables.
Conclusion
Kotlin is a language that