问题
The below picture shows that "Checked" and "Unchecked" Exceptions are subclasses of Exception
. I find it confusing that you need to catch an Exception
but you don't need to catch a RuntimeException
, which directly inherits from Exception
. Is there a reason that the devs didn't let us throw Exceptions without needing to catch them?
More specifically: Why can you ignore only RuntimeExceptions
and it's children? Why wasn't there a Class introduced called CheckedException extends Exception
and you only need to catch it and it's children?
The confusing part is, that you can throw everything below RuntimeException
without issue, but when you move up to Exception
in the hierarchy, you need to catch it at some point. This is confusing because "abstraction" normally works otherwise. The more you move up, the simpler and more meta everything gets. This is not the case here. The more you move up, the more you have to do (like, putting try/catch after reaching Exception
).
回答1:
If Exception
was unchecked then you could implicitly cast checked exceptions to unchecked ones, which would mean that you could throw checked exceptions without catching them like:
public void f() {
Exception e = new IOException();
throw e;
}
and also with overriding methods, if you throw a more specific exception, you can add the requirement to catch the exception that wasn't in the superclass:
public void f() throws Exception {
}
...
@Override
public void f() throws IOException {
}
回答2:
Suppose they designed it the other way. We have a CheckedException
class, and subclasses of that need to be handled, but not other subclasses of Exception
.
Now we call a method that might throw an arbitrary Exception
:
public static void example() {
functionThatThrowsException();
}
Do we need to handle it? Yes, because that Exception
might be a CheckedException
. If we didn't need to handle it, we'd be bypassing the checked nature of checked exceptions.
A throwable type with checked descendants must be treated as checked, so checkedness naturally propagates up the inheritance hierarchy. Contrapositively, an unchecked throwable type cannot have checked descendants, so uncheckedness naturally propagates down. This makes it natural to make checkedness the default, and single out specific classes and their descendants as unchecked.
回答3:
CheckedException
(Which does exist) and RuntimeException
both extend Exception
. Because of this, if something throws a generic Exception
(which is always a bad idea), there is no way to tell if the exception could be one or the other, so you have to catch it in case it's a checked one. If you think of the hierarchy in this way, it actually does get simpler the farther up you go.
You seem to have the idea that checked exceptions are more "complex" because you have to do more to work around them. This isn't too healthy a way of thinking about it. Instead, consider this: Exceptions are problems with the program itself - the code. We need to find these exceptions and handle them properly. After already having this concept of exception handling, we discover that there are some problems that we simply can't predict.
"How was I supposed to know the user would enter 'meow' when asked for an integer! I shouldn't have to code around that!" And so, NumberFormatException
was born, and you don't have to catch it because it's a "logical error", not an issue caused by bad code (Although, arguably, it might be considered bad code if you don't handle this situation in some way).
In short, reverse your thinking. Exception
s are problems with the program that can be handled. There are some exceptions, however, that are unexpected and are a result of bad design more than incorrect code. Thus there is the addition of RuntimeException
s which cannot possibly be expected to occur, but certainly can occur.
回答4:
Perhaps it would help to not think of exception classes in terms of inheritance but simply disjoint sets of classes, one set is checked and other is not. You're right that there could be a CheckedException
class allowing us to check only when explicitly intended.
However having the broader/generalized range checked helps in enforcing the catch or specify pattern. Having checked exception allows a reader of the code to figure out quickly that this piece of code needs special attention and enforcing their handling at compile time reducing the runtime bugs.
We can throw any kind of exception, checked or unchecked. If Exception
or any super class of RuntimeException
were to be set as checked exception then all the sub classes would become checked exceptions. As compiler is most likely checking if an instance of exception or a class in the throws clause derives from a class. It could easily have done that by checking for a specific package which probably would have been more appropriate as being checked or unchecked has simply nothing to do with the inheritance.
回答5:
Your picture already contains an answer - Throwable
is checked and must be caught, because of that Exception
is checked and so on, besides RuntimeException
and its descendants.
Checked exceptions must be caught or rethrown (JLS §11.2). This is guaranteed by java compiler so we are ensured that our "exceptional" situation will be handled.
This compile-time checking for the presence of exception handlers is designed to reduce the number of exceptions which are not properly handled.
If you inverse the logic, then you can't give these guarantees at compile time:
public void notReallySafeMethod() {
try {
connect();
} catch (IOException io) {
Exception e = io;
throw e; // IOException is unhandled
}
}
public void suspiciousMethod() throws Exception {};
public void callSuspicious() {
suspiciousMethod(); // what real type would be thrown? we can't know
// should I try-catch everything then?
}
来源:https://stackoverflow.com/questions/37170572/why-do-you-need-to-catch-exception-but-not-the-subclass-runtimeexception