* Expected errors - Checked Exceptions
* Unexpected errors - Unchecked Exceptions
Idiomatic Java also makes heavy use of asserts, e.g. using the Guava Preconditions library.
* Expected errors - Checked Exceptions
* Unexpected errors - Unchecked Exceptions
Idiomatic Java also makes heavy use of asserts, e.g. using the Guava Preconditions library.
The precondition thing, while indeed common, drives me sorta insane. I think it's a pattern java folks need to move on from. You've got this lovely type system (used loosely). If you need a precondition because you've got some fundamental invariant in the system, doing it at runtime rather than encoding it into the type system is such a missed opportunity. If I try to do something inherently wrong, I don't want the code to even compile!
This is echoed in an amazing book called Domain Design Made Functional, which radically changed how I thought about what a type system is and what it can actually do for us if we lean on it correctly (even a relatively crummy one like Java's!).
Perhaps some sort of language level solution could have been found (eg: have explicit interfaces to mark exceptions as expected or unexpected and then exceptions are assigned that using generics or something), but that ship has sailed long ago.
Kotlin improved on Java by treating all exceptions as unchecked. Including those from Java code. This was intentional and based on the observation that checked exceptions in Java were simply a mistake. Modern Java frameworks don't tend to use them for this reason. Kotlin fixed several other language design mistakes in Java and it's a reason it is used as a drop in replacement for Java in a lot of places. It also makes what guava and lombok do for Java completely redundant. All part of the language and standard library. Android, Spring, Quarkus, etc. they all become nicer to deal with when you swap out Java for Kotlin. I find dealing Java code to be very awkward these days. I used it for years and it just looks so ugly, clumsy, and verbose to me now.
The most common catch block in Java is e.printStackTrace() because that's what your IDE will insert. That's stupid code. And replacing it with a logger.error(e) is only marginally better. Idiomatic Java is actually re-throwing exceptions as RuntimeExceptions so your framework can handle them for you in a central place and show a nice not found page or bad request page (or the dreaded "we f*ked up" internal server error page). That too is stupid code to write and with Kotlin, re-throwing exceptions is not really a thing. Why would you? Either you handle the exception or it just bubbles up to a place where it is handled or not. If you want people to deal with exceptions, you wrap them with a a Result<T> in Kotlin. Java has a similar thing called an Optional but it is mostly just used to dodge null pointer exceptions; which in Kotlin are rare because it has nullable types. And of course it does not actually contain the original exception.
Just fyi, Scala predates Kotlin in not enforcing checked exceptions.
Our good friend UncheckedIOException.