Today I was exploring a Jetpack Compose sample project source code, and at one point I found a code that implements a Mutex.

Here’s what it looks like (from kotlinx-couroutines-core)

    lock(owner)
    try {
        return action()
    } finally {
        unlock(owner)
    }

I was wondering how they are going to release the mutex lock within the finally block once the return action() inside the try block is executed.

I never wrote a finally block before, so this got me a little confused.

A search revealed that many people has come across this situation. There’s a question in StackOverflow which has around ~2.4k upvotes, and bookmarked ~500 times.

It is true. The finally block gets executed always, except some unforeseen situations like the process getting killed, which is mentioned in the accepted answer in the StackOverflow question.

From the Java documentation,

[finally] allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.

…also adds a note that says:

Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.

Let’s try out a try block!

So here’s a code sample that you can play around:

fun main() { println(tryExample()) } fun tryExample(): String { try{ return "Returned from try{}" } finally { println("Inside finally{}") } }

This code will print:

Inside finally{}
Returned from try{}

One more thing, if the finally returns something, then the return within the try block won’t work.

When I posted this on LinkedIn, my colleague Afsal pointed out another interesting thing – if we return from the finally block, then the return statement within the try block won’t execute.

That was another discovery.

Here’s a code to try that out:

fun main() { println(tryExample()) } fun tryExample(): String { try{ return "Returned from try{}" } finally { println("Inside finally{}") return "Returned from finally{}" } }

The output will be:

Inside finally{}
Returned from finally{}

So a new lesson learned - the finally block always executes (except for a few conditions) and if a finally block returns, the try/catch won’t return.


I tried this on Java, Kotlin, and Javascript. You can read my other article with Javascript examples on Dev.to.