3 ms·
Let me try to phrase the argument more clearly: if you want to pass on a checked exception via redeclaration in the "throws" clause, you've broken encapsulatio
by akeefer 17y ago
Let me try to phrase the argument more clearly: if you want to pass on a checked exception via redeclaration in the "throws" clause, you've broken encapsulation because a change to the lower layer implies changes all the way up the stack. If bar() was originally calling readDatabase() that threw a SQLException, and I change it to call readFile() that throws an IOException, if I'm passing that exception up the stack I have to change bar's signature purely due to an implementation change, and so on up the stack. So a change at the lower layer has now forced me to make changes all the way through my application stack. Henceforth, encapsulation is broken by what should just be an implementation change.
The only way to avoid that break of encapsulation is to catch the exception immediately in bar(), and then do something with it: either handle it, or rethrow it as something else, either a runtime exception or as a different checked exception. But that also isn't really ideal; in my experience, about 98% of the time even checked exceptions are throw-up-your-hands sort of programmer errors that you want to bounce a fair way up the stack to some more central error-handling location, or to kill the high-level operation being attempted. In other words . . . you generally just want to treat them exactly like runtime exceptions.
So while the theory of type-safety around checked exceptions is nice and all, in practice if you actually use them as part of type signatures they massively couple all the layers of your application, and I find them much more annoying than useful.