← Back to Kotlin Course | Chapter 14: JVM Interop & Best Practices | Lesson 7 of 7

Kotlin Best Practices

Kotlin best practices are the collected wisdom of experienced developers about how to write Kotlin code that stays clear, safe, and easy to maintain over time.

Design for Safety First

Preferring non-null types, val, and sealed classes wherever the domain allows it turns many entire categories of bugs into compile-time errors instead of runtime crashes.

Example: Design for Safety First

markup
sealed class PaymentResult
// Define a data class `Approved`
data class Approved(val transactionId: String) : PaymentResult()
// Define a data class `Declined`
data class Declined(val reason: String) : PaymentResult()

// Define the function `describe` taking `result` and returning a String
fun describe(result: PaymentResult): String = when (result) {
    is Approved -> "Approved: ${result.transactionId}"
    is Declined -> "Declined: ${result.reason}"
}

// Entry point: execution of the program starts here
fun main() {
    // Print `describe(Approved("tx_123"))` to the console, with a trailing newline
    println(describe(Approved("tx_123")))
}

Keep Functions Small and Focused

Breaking logic into small, well-named functions (including local and extension functions) makes each piece easy to understand, test, and reuse on its own.

Example: Keep Functions Small and Focused

markup
fun Int.isPrime(): Boolean {
    if (this < 2) return false
    // Loop over `2 until this`, binding each item to `i`
    for (i in 2 until this) {
        if (this % i == 0) return false
    }
    // Return `true` from this function
    return true
}

// Entry point: execution of the program starts here
fun main() {
    // Declare a read-only variable `primes`, set to `(2..20).filter { it.isPrime() }`
    val primes = (2..20).filter { it.isPrime() }
    // Print `primes` to the console, with a trailing newline
    println(primes)
}

Don't Ignore Compiler Warnings

Warnings about unreachable code, unnecessary safe calls, or unchecked casts often point directly at a real bug or a design that can be made safer -- treating them seriously pays off.

Example: Don't Ignore Compiler Warnings

markup
fun describeNumber(n: Int): String {
    return if (n % 2 == 0) "even" else "odd"
    // Any code placed here would be unreachable, and the compiler would warn about it
}

fun main() {
    println(describeNumber(7))
}

Write Code for the Next Reader

Choosing clear names, favoring well-known idioms over clever tricks, and keeping functions short all serve the same goal: making the code easy for someone else (or future you) to safely understand and change.

Example: Write Code for the Next Reader

markup
// Define the function `calculateShippingCost` taking `weightKg`, `isExpress` and returning a Double
fun calculateShippingCost(weightKg: Double, isExpress: Boolean): Double {
    // Declare a read-only variable `baseCost`, set to `weightKg * 2.0`
    val baseCost = weightKg * 2.0
    // Return `if (isExpress) baseCost * 1.5 else baseCost` from this function
    return if (isExpress) baseCost * 1.5 else baseCost
}

// Entry point: execution of the program starts here
fun main() {
    // Print "Shipping cost: ${calculateShippingCost(5.0, true)}" to the console, with a trailing newline
    println("Shipping cost: ${calculateShippingCost(5.0, true)}")
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Reaching for !! or unsafe casts as a quick fix instead of addressing the underlying design that made a value's type or nullability uncertain.
  2. Writing large, do-everything classes and functions instead of composing small, well-named, single-purpose pieces.
  3. Ignoring compiler warnings, which often point to genuine risks like unreachable code, unused variables, or unsafe casts.
Chapter Summary
  • Prefer immutability (val, read-only collections) and null safety operators over defensive, manual workarounds.
  • Keep functions small and focused, with descriptive names that make comments about *what* the code does mostly unnecessary.
  • Use sealed classes and exhaustive when expressions to make invalid states unrepresentable wherever practical.
  • Pay attention to compiler warnings -- they frequently highlight real, fixable risks in the code.
🔒

Chapter Quiz — Complete all 7 topics to unlock

0/7 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.