You asked for didactic examples. What I have is what I have learned from experience.
In the case of checked exceptions I see that it is common for data manipulation libraries to release exceptions related to I/O and Parsing data. Java’s "classical" I/O library for example launches IOException
, FileNotFoundException
and EOFException
, to name the most common. Libraries networking and HTTP communication by also performing I/O launch at least IOException
. A JSON parser like json.org that comes along with Android can launch a JSONException
related to reading a data from a JSON string, whereas Google’s Gson can launch a JsonSyntaxException
.
Anyway, they are situations where the library itself is not prepared to deal with the error and chooses to pass it to a higher level of the call stack or call stack. She does this by declaring that these exceptions, if they occur, will need to be handled by those who make use of that API. This is one of the advantages of working with exceptions: just as you can treat them at the point they occur, you can also delegate this treatment to a level that you are best able to treat, or "recover", from the error that occurred.
By declaring this in the form of a checked Exception, you are signaling the "user" code that that error deserves attention and probably some kind of treatment. And it’s typically a "recoverable" error: Your application can prepare for a malformed JSON, a file not found, or an interruption in network communication.
It’s different than a Runtime Exception in the sense that the Runtime typically represents an error in the functioning of the code itself, an error you pick up during execution and need to correct the code and prevent it from happening, as @Maniero said. You need to "shield" your code against it. A parameter that cannot be passed as null
otherwise it will launch a IllegalArgumentException
or a NullPointerException
, a state that theoretically should not happen under pain of launching a IllegalStateException
(example: a method that should only be called by the Android UI thread and you involuntarily call from a secondary thread), to name the types that I most use today. When my code makes one of these exceptions, I admit I don’t expect it to happen, but sometimes it does and I know it’s a code defect.
I confess I’ve already treated IOException
within a library of mine calling to web services instead of delegating to the user code. I "swallowed" the exception (when very logged) and returned null
in my reply. It was a bad design decision. My user code did not know when a null
from a successful request or when it came from an I/O error, and are two different situations that require different treatment. It wasn’t my library that needed to handle I/O exceptions but the code that made use of it.
Already in a newer code where I make use of Apache HTTP Client I declared the following:
private HttpResponse executarRequisicaoSincrona(DataTransferRequest requisicao)
throws UnsupportedEncodingException, IOException {
See how this method delegates to another level two checked exceptions, a specific I/O (which is encoding unsupported) and more general I/O. Both are likely to occur during an HTTP request in different situations and I thought it best not to treat them on the same level as they are launched, but to pass them forward, because at this point my code does not know yet what to do with them. If I knew, I could treat them within the method itself executarRequisicaoSincrona
instead of declaring them, but that is not the case in my code.
I hope that with these experiences you can have a more accurate notion of when to use or cast exceptions of the two types, checked and unchecked.
Updating: This link explains very well the difference between the two and when to use one or the other (in fact it explains what are the best practices on handling exceptions in Java). I strongly recommend it.
Thanks @bigown, your reply helped me understand a little better, what it is, and when to use each one. + 1
– Fernando Leal