Consider:
try {
// Some code here
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw e;
}
What is the difference between throw e
and throw new Exception(e)
?
try {
// Some code here
} catch (IOException e) {
throw new IOException(e);
} catch (Exception e) {
throw new Exception(e);
}
If you don't need to adjust the exception type, you rethrow (throw further) the same instance without any changes:
catch (IOException e) {
throw e;
}
If you do need to adjust the exception type, you wrap e
(as a cause) into a new exception of the type required.
catch (IOException e) {
throw new IllegalArgumentException(e);
}
I consider all other scenarios a code smell. Your second snippet is a good example of it.
Here are answers to the questions that might pop up.
Why would I want to rethrow an exception?
You can let it go. But if it happens, you won't be able to do anything at this level.
When we catch an exception in a method, we are still in that method and have access to its scope (e.g. local variables and their state). Before we rethrow the exception, we can do whatever we need to (e.g. log a message, send it somewhere, make a snapshot of the current state).
Why would I want to adjust an exception?
As a rule of thumb,
Higher layers should catch lower-level exceptions and, in their place, throw exceptions that can be explained in terms of the higher-level abstraction.
Effective Java - 2nd Edition - Item 61: Throw exceptions appropriate to the abstraction
In other words, at some point, an obscure IOException
should be transformed into a perspicuous MySpecificBusinessRuleException
.
I called it "adjusting the exception type", smart guys call it exception translation (exception chaining, in particular).
To make it clear, let's have some foolish examples.
class StupidExample1 {
public static void main(String[] args) throws IOException {
try {
throw new IOException();
} catch (IOException e) {
throw new IOException(new IOException(e));
}
}
}
results in a verbose stack trace like
Exception in thread "main" java.io.IOException: java.io.IOException: java.io.IOException
at StupidExample1.main(XXX.java:XX)
Caused by: java.io.IOException: java.io.IOException
... 1 more
Caused by: java.io.IOException
at StupidExample1.main(XXX.java:XX)
which can (and should) be effectively reduced to
Exception in thread "main" java.io.IOException
at StupidExample1.main(XXX.java:XX)
Another one:
class StupidExample2 {
public static void main(String[] args) {
takeString(new String(new String("myString")));
}
static void takeString(String s) { }
}
It's obvious that new String(new String("myString"))
is a wordy version of "myString"
and should be refactored to the latter.