Top Mistakes of Beginner Kotlin Developers: From A to Z
Kotlin is a modern, concise, and safe language that has rapidly won the hearts of Android developers and backend engineers. However, even in such a friendly language, beginners often make typical mistakes that slow down learning and lead to bugs. In this article, we will break down the most common problems — from misunderstanding null safety to overusing lateinit. You will learn how to avoid them and write clean, efficient Kotlin code.
1. Ignoring null safety and incorrect work with nullable types
One of Kotlin's main features is built-in protection against NullPointerException. But beginners often try to use a Java-like approach, which leads to errors.
Mistake: Using !! (non-null assertion) where it is not needed
Many write:
fun getUserName(user: User?): String { return user!!.name // If user == null — will get NPE}It is better to use a safe call (?.) or the Elvis operator (?:):
fun getUserName(user: User?): String { return user?.name ?: "Guest"}Mistake: Incorrect use of lateinit var
The lateinit field is intended for situations where you know for sure that the variable will be initialized before its first use (for example, in Android in onCreate). But if you access lateinit before initialization, you will get an UninitializedPropertyAccessException.
Tip: Use lateinit only with var and check the ::variable.isInitialized property before access.
2. Incorrect use of collections: mutable vs immutable
Kotlin clearly separates List (read-only) and MutableList. Beginners often confuse them, which leads to compilation errors or unexpected behavior.
Mistake: Trying to modify an immutable list
val list = listOf(1, 2, 3)list.add(4) // Compilation error! listOf returns List, not MutableListIf you need a mutable collection, use mutableListOf:
val mutableList = mutableListOf(1, 2, 3)mutableList.add(4) // WorksMistake: Returning MutableList from a public API
This breaks encapsulation. It is better to return List:
// Badfun getItems(): MutableList<String> = mutableListOf("a", "b")
// Goodfun getItems(): List<String> = mutableListOf("a", "b").toList()3. Overusing companion object instead of top-level functions
Kotlin has no static methods, but it has companion object. Beginners often put everything there, even though more concise top-level functions or properties can be used.
Example of a mistake:
class Utils { companion object { fun formatDate(date: Date): String { ... } }}
// Call: Utils.formatDate(...)It is better to move the function to the file level:
// file: DateUtils.ktfun formatDate(date: Date): String { ... }
// Call: formatDate(...)This makes the code cleaner and does not require creating an extra class. Use companion object only for factory methods or constants related to the class.
4. Misunderstanding sealed classes and when-expressions
Sealed classes are a powerful tool for representing a restricted class hierarchy. However, beginners often forget about the else branch or use if-else instead of when, losing all the advantages.
Mistake: Using else in when for a sealed class
sealed class Result { data class Success(val data: String) : Result() data