3 ms·
It's not trivial if you're forced to conform to an interface which has a narrower "throws" clause than what you need. It's an issue of contravariance vs. covari
by Quekid5 7y ago
It's not trivial if you're forced to conform to an interface which has a narrower "throws" clause than what you need. It's an issue of contravariance vs. covariance. Implementations of an interface/superclass are typically more concrete, and so they need to be able to throw more more types of exceptions... but throws clauses work in the opposite way: You're only allowed to narrow them, not expand them in subclasses/implementations-of-interfaces.
It's simply broken.
EDIT: Just to add: What happens in practice is that either
- you just give up and declare "throws Exception" on the interface (in which case: why bother? You might as well just remove checked exceptions at that point), or
- you wrap checked exceptions in RuntimeException, but now you have a new problem: Consider a method that calls methods f and g where f declares a "throws Foo", but g doesn't declare any exceptions[0], but may throw Foo's at runtime by wrapping. Now you're totally screwed, because a "catch Foo" will not match exceptions from g. The Guava people have written a whole Throwables utility class to help with this, but using that consistently requires discipline that no team can handle, and it only handles a small subset of the problem.
This is just a small sample of the problems with checked exceptions in Java.
[0] g may be used in contexts where it's not "allowed" to declare checked exceptions in a throws clause, e.g. lambdas or just higher-order functions in general.