In this lesson we’ll focus on how to use Kotlin’s exception handling mechanisms—both
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.
But! Let’s warm up with another graded debugging challenge!
Before we go on, let’s look at a few further wrinkles in Kotlin exception handling that we haven’t touched on yet.
First, you may have wondered: what happens if you throw an exception inside a
Let’s try it:
You’ll notice that the second exception is thrown out of the
Of course, we can rewrap the entire
try-catch in another
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:
try-catch blocks can include an additional component: a
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
finally block is always executed.
One of the cool things about
finally is that it is always executed.
Even if the try includes a
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!
Create a public class
PingPonger is in one of two states: ping or pong.
You should provide a constructor accepting a
String argument that sets the initial state.
If the passed
String is "ping", the initial state is ping.
If the passed
String is "pong", the initial state is pong.
If the passed
String is not ping or pong, you should throw an
PingPonger has been created, the user should call
pong if the state is ping
ping if the state is pong.
ping takes no arguments and returns
pong takes no arguments and returns
pong is called out of order, you should throw an
Here's an example:
Next let’s look at a few common exception handling patterns.
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
check, rather than rely on
However, we can replace many of the places where we had previously used
assert with Kotlin’s convenient
When checking parameters to a method, use
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:
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:
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:
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.
Exception could not be easier:
Create and complete the implementation of the
Your class should be public, inherit from the
Shape class, and provide the following methods:
Doubleparameter. Creates a new
Pentagonwith the passed side length. If the passed length is less than or equal to 0, throw an
IllegalArgumentException. You should call the
Shapeconstructor and pass it the
String"pentagon" to identify the type of this shape.
areathat takes no arguments and returns a
double. Return the area of this shape, given only the side length, which you can find here: https://www.cuemath.com/measurement/area-of-pentagon/. You will need to use
sqrtor Kotlin's built-in
sqrtto solve this problem.
fun equals(other: Any?): Boolean. Return
Pentagonwith the same side length, and
falseotherwise. Note that
nullor not a
Finally, note that your class should not expose any of its internal state publicly.
When we call a method that might throw an exception, sometimes the right thing to do is to catch it, and other times we should let it be thrown out of our method.
But sometimes we want to catch that exception and save it for later, to be dealt with by another part of our program. This is particularly useful when the code that is using the result of the method call is not the caller of the method, a situation that we'll encounter once we begin Android development.
To help handle this situation, create a public class called
It stores the result of calling a method that might throw: either an
Any? result if the method succeeded, or an
Exception exception if it threw.
ResultMightThrow provides two constructors: one accepting a single
Any?, the other a single
We suggest not using a primary constructor for this class, and rather providing two secondary constructors.
The result property should be readable.
However, if the
ResultMightThrow actually stores an exception, you should throw that exception instead when
the result is read.
Do not try to override the property getter using the usual
This will trigger a bug in the Kotlin compiler.
Instead, simplify define a
getResult function in the usual way:
Note that this is always an option in Kotlin when defining getters and setters for a property, although it's usually more convenient to not define them as separate methods and let Kotlin generate them for you.
The exception property should also be readable.
When complete, here is how your class should work:
Note that the multiple constructors used in this problem illustrates the intersection between Kotlin's method
overloading and polymorphism.
When choosing between the two constructors that both accept a single parameter, Kotlin will choose the one with the
type most closely matching the passed value.
So even though every Java
Exception is also an
Any, calling the
ResultMightThrow constructor with an
Exception will enter the constructor accepting an
Exception as a parameter.
Need more practice? Head over to the practice page.