Those sneaky Kotlin Exceptions

https://www.flickr.com/photos/crozefeet/23244411091

If you are developing in Kotlin, you may already know that unlike Java, checked exceptions are not supported. Many articles have been written for and against both approaches, so we are not here to discuss this. Instead, I want to focus on interoperability when moving between Java and Kotlin.

The good old Java way

When you throw an exception from Java, the compiler forces you to declare this:

Same when you want to call a method that throws, the compiler forces you to handle this:

But in Kotlin

Kotlin, on the other hand, does not know this concept. But as Java and Kotlin work smoothly together, how does this work under the hood?

The important fact to notice here is that checked exceptions are part of the Java language, not the JVM! In bytecode, you can throw any exception without restrictions!

And other JVM languages made use of that, Groovy, for example, also allows throwing exceptions without declaring them.

When we look at the decompiled byte code of a Kotlin method which throws an Exception it might look something like this:

public final void throwSomething() {
throw (Throwable)(new IOException());
}

So the Kotlin compiler hides the exception behindThrowable, which is the interface that both, checked and unchecked exceptions implement.

Actually…

you can do something similar in Java. It’s known as sneaky throws:

public static <E extends Throwable> void sneakyThrow(Throwable e) throws E {
throw (E) e;
}

private static void throwsSneakyIOException() {
sneakyThrow(new IOException("sneaky"));
}

The problem

There is one problem with sneaky throws (and the same applies to exceptions thrown from Kotlin): if you want to catch the exception, the Java compiler will not allow you to directly catch that (checked) type:

The solution

With Kotlin there is an easy way to solve this. Use the @Throws annotation!

@Throws(IOException::class)
fun throwSomething() {
throw IOException("")
}

This will be translated into byte code the same way as a Java throws keyword on methods.

So if your code might be called from Java, you should add this to use the strength of both languages!

But wait… there is more!

There are other issues you can run into. For example, if you are using Mockito, a library that was written in Java, and you mock a Kotlin class that throws something like:

`when`(mock.doSomething()).thenThrow(IOException(""))

you might end up with an error like:

org.mockito.exceptions.base.MockitoException: 
Checked exception is invalid for this method!

This one is easy to workaround by using an Answer

doAnswer { 
throw IOException("")
}.`when`(mock).doSomething()

TL;DR

Even if Kotlin and Java are working really well together, sometimes it’s important to be aware of the other side as these hidden exception pitfalls have shown.

So be careful and play nice!