June 30, 2020 - 5 min read ⏱️
The dark side of Unchecked Exceptions
Hi all, for my first post/article/whatever here, I have decided to talk about an old argument in the Java community: the dreaded Checked vs Unchecked exceptions.
For those of you who have never heard of this, here is a brief recap:
The dispute on their usage has been controversial, with checked exceptions usually regarded as the black sheep.
Arguments against checked exception that you could have heard are:
Checked exceptions can be ignored by swallowing them, so what’s the point of having them?
try {
// do stuff
} catch (AnnoyingCheckedException e) {
// do nothing
}
Checked exceptions are easy to ignore by re-throwing them as RuntimeException instances, so what’s the point of having them?
try {
// do stuff
} catch (AnnoyingcheckedException e) {
throw new RuntimeException(e);
}
Checked exceptions result in multiple throws clause declarations.
The problem with checked exceptions is they encourage people to swallow important details (namely, the exception class). If you choose not to swallow that detail, then you have to keep adding throws declarations across your whole app.
As far as I can tell, in the Java world the following best practice has been established:
RuntimeExceptions
for your internal modules.The reason being that checked exceptions clutter your code (so avoid them inside your module) but document the external behaviour of your API.
The point I want to make here is that:
RuntimeExceptions
are evil
If you feel offended by this argument you’re free to stop reading and go out for a walk, they say it’s really good for your health!
Why are they evil?
Well because whenever you’re throwing a RuntimeException
from one method you’re telling a lie.
Which lie?
Say you have a method like:
public Money from(BigDecimal amount, String currency) {
if (amount.signum() < 0) {
throw new ValidationException("whatever");
}
return new Money(amount, currency);
}
This method is lying! It is telling its user it will return an instance of Money
given a BigDecimal
and a String
, but it is not, or at least not always.
You may say: I can always document this behaviour with a test, but still that is a loose end.
Another example might be:
interface Repository<T> {
T save(T elem);
}
You know from your experience that the save
method might throw an exception, but you have been told not to use checked exceptions, so you are failing to document it.
Another couple of considerations:
RuntimeExceptions
are nothing else than glorified GOTOsRuntimeExceptions
are more difficult to reason about because you have to keep that information in the back of your mindRuntimeException
has been thrownChecked exceptions, on the other hand, by forcing you to handle them are more honest and they are actually telling you that the method you are calling returns 2 possible values:
By now I guess you might be wondering where I left the FP glasses I mentioned in the title: here they come.
In the FP world (disclaimer: I am just at the beginning of my journey in this world) there is a type meant to be used to express exactly the choice between two types: Either<E, A>
where:
Aside from being exactly what you might have been looking for to explicitly state what your method returns, Either is also a monadic data type. Without going into the rabbit hole of talking about Monads, let’s say a monadic data type exposes 2 functions that make it easy to work with the right value once you get an Either into your hands.
The 2 methods are:
f: A -> B
and will turn your Either<E, A>
into an Either<E, B>
f: A -> Either<E, B>
and will still turn your Either<E, A>
into an Either<E, B>
You might be familiar with this 2 new functions because the new Stream API (since java 8) or Optional (again starting from Java 8) support those 2 functions.
And you may appreciate how they promote a more declarative way of programming.
Either
instead is not in the Java JDK but you can find it in (not an exhaustive list):
The FP way of thinking about functions as mapping between inputs and outputs (and nothing more) brought me to the conclusion that you should always
Return a value from your function or not return it (maybe the parallel does not work here). There is no try!
Or, to put it not in Yoda’s terms,
A function should be total and always return a value!
Well that’s all folks.
Hope you have enjoyed it!
(originally posted on https://dev.to/eureka84/unchecked-vs-checked-exception-with-fp-glasses-2528)
The postings on this site are authors' opinions and experiences and do not necessarily represent the postings, strategies or opinions of lastminute.com group.