Never Use Exceptions for Logic in Kotlin!

Adrian Tache
Android Ideas
Published in
3 min readJan 2, 2024

Every now and then I get surprised by exception handling, and the fact that people use it for other reasons than an oh no, this really shouldn’t be happening, or at most a that’s really not how you’re supposed to use this.

And that surprise is that people throw exceptions all over the place to signal issues to other parts of the app, for example for network problems like having no connection or timeouts. This is of course bad practice because it creates dangerous, unpredictable spaghetti (what if someone forgets to catch them!), but it’s also a very inefficient way of dealing with problems we know exist.

Of course, the solution most people will recommend here is to use the Result class¹ from Kotlin. This improves code readability, of course, since now our errors are caught and ideally mapped where they occur, so it’s easier to know why they happen and handle them as soon as possible. This also makes it much safer to use our code, since no exceptions are thrown, and it’s on us if we ignore those failure states. But, surprise, surprise, this class also expects a Throwable to be passed to it in case of failure, so it doesn’t avoid the crux of the issue.

So what’s this big problem I keep going on about? Well, the issue is that every Throwable(or Exception) object you create builds a stack trace. You can see this by going to the class definition and, if you look at its simplest constructor, you’ll notice it has only one method that it calls:

    public Throwable() {
fillInStackTrace();
}

So if you just want to build a simple exception that does nothing, you’re still getting a full stack trace of the moment you’re creating it, which is wasteful and quite expensive. I recommend these articles to understand a bit more why this isn’t a great way to write code:

https://wiki.c2.com/?DontUseExceptionsForFlowControl

How do we go around this? Pretty easily, really, just build your own interface² for program errors, maybe call it Error , and pass it to your program logic instead of fully fledged exceptions. This way you still get the benefit of building whatever exceptions you want, which you can easily find by inheritance from this base class, and you can even build your own Result class to return them when you can’t handle them immediately.

Of course, this isn’t an article against exceptions as a concept, I feel they’re very useful when you want the code to crash (and provide a stack trace) if it’s misbehaving, in order to either prevent unexpected and unwanted states, or to discover edge cases and patch them. But as always, don’t use a hammer for everything, and try to write simple, readable code. Your future self will thank you!

¹ — I’m not a big fan of the Result class as is, since it’s quite cumbersome for some uses, and doesn’t benefit from SmartCast once you’ve established which of the two options it is. I recommend building your own, here’s an example that I sometimes use, which grants the benefits of sealed classes, but of course isn’t as efficient as the official class: https://gist.github.com/adriantache/04c17a282635529bab2622264a4f9cd2

² — I recommend against making Error a class, so that you can enforce a separation between UI and other layers. This way, your UI won’t just display the message of the error with no considerations for what it is, and will instead need to treat each error separately, as it’s best for the user’s experience. You can of course still handle common errors very easily by just building a mapper for them.

Thanks for reading this article. You can connect with me on LinkedIn.

I’m currently looking for a job in London, UK, so please contact me if you know someone in need of a Mobile Developer with Java/Kotlin (Android) experience.

If you liked this article, please hit the clap icon 👏 to show your support.

--

--