Kotlin
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Null Safety
-
Section 4: Object-Oriented Kotlin
-
Section 5: Functional Kotlin
-
Section 6: Coroutines
-
Section 7: Collections Deep Dive
-
Section 8: Type System Deep Dive
-
Section 9: Interop and Tooling
-
Section 10: Kotlin DSLs and Patterns
-
Section 11: Testing and Quality
-
Section 12: Server-Side Kotlin
-
Section 13: Practical Projects
-
Section 14: Interview Practice
-
Section 15: More Practice Exercises
-
Section 16: More Standard Library
-
Section 17: Multiplatform Kotlin
-
Section 18: kotlin.collections In Depth
-
Section 19: kotlin.text In Depth
-
Section 20: kotlin.ranges and kotlin.sequences
-
Section 21: kotlin.io and File Handling
-
Section 22: kotlinx.coroutines Deep Dive
-
Section 23: kotlin.reflect
-
Section 24: Android Development with Kotlin Overview
-
Section 25: Kotlin Multiplatform Deep Dive
-
Section 26: Kotlin for Backend Deep Dive
-
Section 27: Kotlin Design Patterns
-
Section 28: Advanced Language Features
-
Section 29: More Practice Exercises
-
Section 30: More Interview Practice
-
Section 31: Kotlin Type System Deep Dive
-
Section 32: Kotlin Null Safety Advanced
-
Section 33: Kotlin Testing Deep Dive
-
Section 34: Kotlin Build Tooling Deep Dive
-
Section 35: Kotlin Serialization
-
Section 36: Kotlin Performance Considerations
-
Section 37: Kotlin Native Overview
-
Section 38: Kotlin for Data and Scripting
-
Section 39: More Coroutines Practice
-
Section 40: More Android-Adjacent Patterns
-
Section 41: More Practical Projects
-
Section 42: More Design and Architecture Practice
-
Section 43: Kotlin Language Evolution
-
Section 44: More Interview and Review
-
Section 45: Kotlin Delegation Patterns Deep Dive
-
Section 46: Kotlin Annotations Deep Dive
-
Section 47: Kotlin for Gradle Plugin Development
-
Section 48: Kotlin Concurrency Beyond Coroutines
-
Section 49: Kotlin Compiler Internals
-
Section 50: Real-World Kotlin Case Studies
-
Section 51: Final Practice Projects
-
Section 52: Kotlin for Server-Side Reactive Programming
-
Section 53: More Practice and Drills
-
Section 54: Kotlin Security Practices
14: The !! Operator and Its Risks
By now, you've probably seen the !! operator popping up in examples or autocomplete. In the Kotlin community, we often call this the "double-bang" operator. Itβs essentially you telling the compiler, "I know you think this variable might be null, but I promise it isn't. Now shut up and let me run the code."
The problem is that compilers are rarely wrong about nullability, but humans are. When you use !!, you aren't removing the possibility of a null value; you're just telling Kotlin to throw a NullPointerException (NPE) the second you're wrong. It's the fastest way to crash your app.
Defining a VIP User System
Let's build a small piece of a membership system. We have a User and an optional PremiumPlan. In a perfect world, any user marked as a "VIP" should always have a plan assigned to them. If they don't, it's a data error.
data class PremiumPlan(val tier: String, val monthlyCost: Double)
data class User(val name: String, val isVip: Boolean, val plan: PremiumPlan?)
I want to write a function that prints the cost of a user's plan, but only if they are a VIP. Since I "know" that every VIP has a plan, I'm going to take a shortcut.
The temptation of the double-bang
Here is where I'll make the mistake. I'm feeling confident. I've checked the database, and every VIP user I see has a plan. I'll just force the type conversion using !! to avoid writing extra safety checks.
fun printVipCost(user: User) {
if (user.isVip) {
// I'm sure this is not null because they are a VIP!
println("The cost for ${user.name} is ${user.plan!!.monthlyCost}")
} else {
println("${user.name} is a standard member.")
}
}
This looks clean. No if blocks for null checks, no complex chaining. It just works... until it doesn't.
Watching the app crash
In a real production environment, "I'm sure" is a dangerous phrase. Imagine a race condition where a user is upgraded to VIP status in the database, but the plan assignment fails or is delayed. Or maybe a legacy user was imported incorrectly.
fun main() {
val luckyUser = User("Alice", isVip = true, plan = PremiumPlan("Gold", 29.99))
printVipCost(luckyUser) // Works great!
val glitchedUser = User("Bob", isVip = true, plan = null)
printVipCost(glitchedUser) // BOOM: NullPointerException
}
The moment printVipCost hits that !! on Bob's profile, the program dies. That's the risk. You've essentially reintroduced the exact problem Kotlin's type system was designed to solve.
Replacing the crash with a fallback
Now, let's fix this. Instead of gambling on the data being perfect, I'll use the Elvis operator (?:). This allows me to provide a sensible default or a graceful error message instead of letting the whole process terminate.
fun printVipCostFixed(user: User) {
if (user.isVip) {
val cost = user.plan?.monthlyCost ?: 0.0
if (cost == 0.0) {
println("Error: ${user.name} is a VIP but has no assigned plan!")
} else {
println("The cost for ${user.name} is $cost")
}
} else {
println("${user.name} is a standard member.")
}
}
By switching to ?. and ?:, the code is slightly more verbose, but it's bulletproof. If Bob shows up with a null plan again, the app keeps running, and we get a helpful error message we can actually log and fix in the database.
π Practical Task
Refactoring the Broken Inventory Manager
You've inherited a piece of code for a warehouse system. The previous developer used the !! operator liberally, and the app is crashing frequently when items are missing their "Supplier" details. Your task is to remove the dangerous assertions and make the code safe.
The Broken Code:
data class Supplier(val name: String)
data class Product(val title: String, val supplier: Supplier?)
fun getSupplierName(product: Product): String {
// This line is causing the crashes!
return "Supplier: " + product.supplier!!.name
}
Your Objective:
Modify the getSupplierName function so that it no longer uses !!. If the supplier is null, the function should return the string "Supplier: Unknown" instead of crashing.
There are no comments for now.