10

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).

enter image description here

Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170
codepleb
  • 10,086
  • 14
  • 69
  • 111
  • I thought if you catch `Exception` that you will catch all exceptions and any decedents of that exception class as well? – Rabbit Guy May 11 '16 at 18:37
  • For whatever reason Java's designers thought checked exceptions were a good idea, they also decided that all `Throwable`s should be checked by default, unless specifically excluded by subclassing `Error` or `RuntimeException`. – shmosel May 11 '16 at 18:41

4 Answers4

5

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 {
}
fgb
  • 18,439
  • 2
  • 38
  • 52
  • 1
    But with this, you could also say, `Exception e = new RuntimeException()` which would need to be catched for no reason. If someone does what you show, wouldn't that be "on purpose" somehow? With exactly that intention (for whatever reason). People can always do bad things on purpose if they want. – codepleb May 11 '16 at 20:15
4

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.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • And what if CheckedExceptions would be completely separate? Not inheriting from Exception? Would look strange, but would also get rid of the situation. Not that I think this is a problem at all or so, but I dunno. I understand the explanations but they don't seem to me like it would be necessarily force a design like the current one. – codepleb May 11 '16 at 20:52
  • @TrudleR: Then catching all exceptions (but not things like ThreadDeath) would have required two catch blocks. (This was back before the `|` syntax for catching multiple exception types.) The current structure isn't an undesirable situation that needs to be forced, so there's no point trying to find a motive that would have been strong enough to force it. It's just slightly more natural this way. – user2357112 May 11 '16 at 21:28
1

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. Exceptions 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 RuntimeExceptions which cannot possibly be expected to occur, but certainly can occur.

Zircon
  • 4,677
  • 15
  • 32
1

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.

11thdimension
  • 10,333
  • 4
  • 33
  • 71