Skip to Content
Course content

14: The !! Operator and Its Risks

Click on the "Edit" button in the top corner of the screen to edit your slide content.

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.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.