Kotlin
Java

Working with Exceptions
Kotlin

Created By: Geoffrey Challen
/ Updated: 2021-10-01

In today's lesson we'll focus on how to use Kotlin's exception handling mechanisms—both try-catch and throw. We'll also introduce a few new wrinkles to round out our understanding of this particular system. Our focus is on real-word patterns for working with and handling errors.

Re-throw and finally

Before we go on, let's look at a few further wrinkles in Kotlin exception handling that we haven't touched on yet.

Re-throw

First, you may have wondered: what happens if you throw an exception inside a catch block? Let's try it:

You'll notice that the second exception is thrown out of the catch block. Of course, we can rewrap the entire try-catch in another try-catch:

Note that exceptions thrown inside a catch block cannot be caught by the same try-catch in which they were thrown. So this doesn't work:

finally

try-catch blocks can include an additional component: a finally block. The finally block is always executed, regardless of whether an exception was thrown or not. Let's see how that works:

If you run this a few times, you'll notice that regardless of whether we complete the try block successfully or enter the catch, the finally block is always executed.

One of the cool things about finally is that it is always executed. Even if the try includes a return!

This feature of finally makes it useful when a method needs to do some kind of cleanup before exiting. We haven't run into this scenario yet, but you will sometimes. And when you do, finally will be there for you!

Exception Handling Patterns

Next let's look at a few common exception handling patterns.

Why Not assert?

We've used assert in the past, particularly when writing test cases.

It's fine for that, but there's something about Kotlin assertions you need to know: they are not on by default!

assert is enabled in all of our playgrounds. However, in other Kotlin environments—such as on Android—it may be hard or impossible to enable assertions. While they can be useful during testing, the right thing to do in most cases is to throw an Exception using require or check, rather than rely on assert.

Input Validation

However, we can replace many of the places where we had previously used assert with Kotlin's convenient require and check methods. When checking parameters to a method, use require:

State Validation

When designing our Kotlin classes, there are times when we want to enforce patterns of usage that span multiple methods. To make that more concrete, let's look at an example together:

Work through an example showing how to use check to catch problems with state validation spanning multiple methods.

Batching Failures

Sometimes our code needs to take a series of steps to complete some action. If any of those steps fail, the entire operation fails. This can be a good place to use a try-catch to avoid having to do a lot of error checking after each step. Let's look at an example of this:

Walk through how to avoid a bunch of null checks by wrapping everything in a try-catch.

Rethrowing Exceptions

Sometimes when an error occurs we just want to log that it happened, but then let it continue to propagate. We can do this by rethrowing the error out of the catch block:

Designing Your Own Exceptions

Once you start writing your own libraries and sharing code with others, it can be helpful to design your own custom exceptions. One reason to do this is that it allows users of your code to better understand what went wrong. And to do more accurate error handling by establishing multiple catch blocks that deal with different kinds of exceptions.

Happily, extending Exception could not be easier:

Show how to complete the homework problem above. Feel free to cover multiple approaches!

Solution Walkthrough

Show how to complete the homework problem above. Feel free to cover multiple approaches!

Solution Walkthrough