跪拜 Guibai
← Back to the summary

Kotlin 2.5.0-Beta2 Adds Experimental onTrue, onFalse, and ifOrNull to Simplify If-Else

cover.png

Kotlin keeps improving.

Kotlin 2.5.0-Beta2 provides three experimental standard library functions (already listed in the 2.5.0-Beta1 release notes):

They reduce repetitive if-else expressions and make some common Kotlin patterns easier to read.

I've noticed a small trend in modern languages: more support for chained call styles.

Below we use common Android scenarios to illustrate their usage.

1. onTrue() and onFalse()

What they do

Suppose we need to perform an action based on a Boolean result. For example:

Typically, we'd write an if-else block to handle that.

Before: using if-else

There's an Android login screen. After verifying user credentials, we want to log whether authentication succeeded or failed.

fun authenticate(user: User, token: String): Boolean {
    val isAuthenticated = verifyToken(user.email, token)
    if (isAuthenticated) {
        logSuccess("Login successful")
    } else {
        logFailure("Login failed")
    }
    return isAuthenticated
}

This code is fine and is something we're already used to.

Now: using onTrue() and onFalse()

@OptIn(ExperimentalStdlibApi::class)
fun authenticate(user: User, token: String): Boolean =
    verifyToken(user.email, token)
        .onTrue {
            logSuccess("Login successful")
        }
        .onFalse {
            logFailure("Login failed")
        }

Doesn't this look a bit like how Result is handled?

How to understand them

onTrue():

onFalse():

For example:

@OptIn(ExperimentalStdlibApi::class)
val result = true
    .onTrue { println("Success") }
    .onFalse { println("Failure") }
println(result) // true

It's actually simple!

When should you use it? It depends on your preference and needs, but here are some scenarios:

If you only need to perform an action based on a Boolean value and keep the original Boolean result, consider these two functions.

They suit side effects without converting the Boolean into something else.

2. ifOrNull()

What it does

Sometimes we want to return a value only when a condition holds, and null otherwise.

For example, a user profile page: users may or may not have filled in a phone number. We only want to provide the phone number if contact info exists.

Before: using if-else

val phoneNumber = if (user.hasContactInfo) {
    user.phoneNumber
} else {
    null
}

In Kotlin 2.5.0-Beta2, there's a shorter way.

Now: using ifOrNull()

@OptIn(ExperimentalStdlibApi::class)
val phoneNumber = ifOrNull(user.hasContactInfo) {
    user.phoneNumber
}

How to understand it

You can think of ifOrNull() as a function that provides a value based on a condition:

Real scenario: mapping API responses

Suppose in Android development, an API returns a user profile. Some users have contact info, some don't.

data class User(
    val name: String,
    val hasContactInfo: Boolean,
    val phoneNumber: String?
)

We only want to prepare the phone number for the profile page when contact info exists.

@OptIn(ExperimentalStdlibApi::class)
fun getDisplayPhoneNumber(user: User): String? {
    return ifOrNull(user.hasContactInfo) {
        user.phoneNumber ?: "No phone number"
    }
}

This way:

You can use this style when mapping API responses, preparing optional UI data, or creating DTOs.

3. Capability cheat sheet

Function Purpose Return value
onTrue() Runs an action when value is true The original Boolean value
onFalse() Runs an action when value is false The original Boolean value
ifOrNull() Runs a block when condition is true The block's result or null

4. Still experimental

In Kotlin 2.5.0-Beta2, these functions are experimental APIs. You need to explicitly opt in:

@OptIn(ExperimentalStdlibApi::class)

You can also opt in uniformly with the compiler option -opt-in=kotlin.ExperimentalStdlibApi.

This article uses the Beta2 version as an example. Before adopting these APIs in production code, check the latest Kotlin documentation to confirm their status and usage.

5. Some thoughts

These three functions aren't big changes, but they make common Kotlin patterns more expressive. When you run into repetitive conditional blocks, you can directly state what you want to do:

Of course, line count isn't the only goal. What matters more is making code easy to understand and maintain.

Also, as I mentioned at the start, modern languages increasingly favor chained calls. After writing one function call, I can naturally continue using . to call the next function to process the result. In these scenarios, this style is indeed more concise and flows better than using if-else.

Maybe that's one of the reasons RxJava was so popular back then.

Comments

Top 1 of 2 from juejin.cn, machine-translated. The original thread is authoritative.

吭咔唑

You can just use extension functions to do that, the company project is still on 1.7.20.

RockByte

Of course, this isn't necessary either.