Subversion Repository Public Repository

litesoft

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
Ivan Saorin Says: 
April 28th, 2010 at 6:03 pm
I think CHECKED exception is overused in general even at JDK level, but it is not a bad thing. I guess I can deal with JDK. The problem arise from not being clear enough on their use: a not so clear guideline from sun.

This is my actual strategy.

RULE #1 – Never, ever rethrow an exception of the same type of the original one. If you are doing this you are probably logging and rethrowing: that is really a bad attitude.

RULE #2 – Never catch a superclass of a given Exception. The reason is simple: let’s suppose we have a RootException and a WrongBalanceException that extends the former, we release version one of the library to the masses. Eventually some of the users will catch RootException. Now we will introduce a brand new FileValidationFailedException. You can see how the old client code could catch even the new exception without evidence: it should not compile at all as the semantic of the new exception could be totally different.

RULE #3 – Your application must have some “low level” code: the code that interacts with jdk and thirdy party libraries. Here the checked exception is the way to go. catch what make sense and wrap other conditions around RuntimeExceptions wrappers. You will end up having managed the exceptions or having them wrapped: either case are good. There is one notable “exception” to this: the one or two missing cases in which your “high level” code need to know and do something different in that case wrap the low level exception inside your own HighLevel checked exception.

RULE #4 – Your wrapper shoud do a kindness to the world and accept two different messages: one is for the end user and one is for the log file. The first is i18n while the latter is in english. Even if your locale is english this make sense: never show to the end user information that should be logged and viceversa.

The sad thing here is that even following the above rules in your project you will end up with some newbie following every possible antipattern 

What do you think about the rules? They seems to do a good job inside a quite big project.

---------------------------------------------------------------------------------------------------------------------------------------

Barry Kelly Says: 
April 20th, 2010 at 11:40 am
I think you’ve very much mistaken.

Checked exceptions are problematic because they version poorly, they implicitly presume the wrong model of exception handling, and more importantly, they prematurely decide the application’s desired policy for error handling by encoding the “checkedness” in the type itself, where it is not available for configuration by the programmer.

The poor versioning is obvious. You say: “The superclass/interface was not designed properly for extension. Specifically it did not take into account the exceptions overriders/implementers might reasonably want to throw” – and the only problem with that is the well-known difficulty in predicting the future.

But actually, it’s more subtle: exceptions are usually a desired encapsulation violation. When programming to an abstract interface, you don’t want to know the details of how it’s implemented, but all the ways it can fail are a function of how it’s implemented. You can’t reasonably require the design of the most abstract levels of the system to predict every possible low-level implementation failure and state them out long-hand; the only reasonable implementation would be “throws Exception”, which defeats the whole point of checked exceptions.

By presuming the wrong model of handling, I’m referring to the burden of creating a tunnel through the type system for your exception type between the point of the throw and the point of the catch. This burden is set up to optimize for catching sooner rather than later. But the thing is, usually you never want to catch; usually, the only exception catching you want done is at the highest levels of the system, in an event loop or request dispatcher. If you were expecting an exception you’d want to catch, the situation isn’t exceptional; instead, ideally you shouldn’t be using an API that throws. .NET’s pattern of e.g. Int32.Parse() vs Int32.TryParse() exemplifies this.

You try to argue against this with the distinction between runtime errors and exceptions: “checked exceptions do not require the programmer to provide handlers in situations where no meaningful action can be taken. When no meaningful action can be taken Java programs throw Errors”. And this brings me to my third point. The determination for whether meaningful action can be taken varies from program to program, and is encoded in the very exception handlers themselves – i.e. it’s the programmer who should make that choice, not the people who defined the relevant exception types.

All your examples of error – out of memory error, stack overflow, class not found, etc. – actually make more sense as reasons to completely terminate the application, rather than make any attempt to catch. They’re not really errors so much as panics; no one could argue against the fact that meaningful action can’t be taken.

But most of the time, meaningful action can’t be taken; and even when it can, it often isn’t. Consider your web browser. A whole host of things need to happen between entering a URL and the stuff coming up on screen. But what can the web browser meaningfully do about these things? Failure to resolve DNS? Failure to connect? 404? Failure to log in? The best the browser can do is (a) try to carry out your intentions, and (b) if it failed, report back to you with the reasons why. Server programs are usually little different; they try to carry out the request, and return a more or less detailed error reply in the case of failure, with more details sent out to log.


Elliotte Rusty Harold Says: 
April 20th, 2010 at 5:49 pm

Barry,
You need to distinguish between a java.lang.Exception and a java.lang.Error. This is critical. Exceptions are recoverable. Errors rarely are. Meaningful action can always be taken on an exception but usually not on an error. There is no distinction between runtime and checked exceptions in this regard. The distinction between runtime and checked exceptions is exclusively about whether they indicate a bug in the program (runtime exception) or an unpredictable environmental condition (checked exception). The reason catch blocks at some level of the call chain are needed for checked exceptions is because they cannot be eliminated by better coding practices. Catch blocks for runtime exceptions are needed only as defense in depth against program bugs. Runtime exceptions should be logged and the problem that caused them fixed so they don’t reoccur.

Your claim that “usually, the only exception catching you want done is at the highest levels of the system, in an event loop or request dispatcher.” is exactly the problem checked exceptions are designed to solve. Many programmers don’t want to deal with exceptional conditions and would prefer to ignore them. Checked exceptions makes it harder to ignore them. If you’re ignoring them until the top level of your code, you’re probably doing something wrong. If you never want to catch exceptions, then your code is a lot less robust than it should be. Both extremes–catch all exceptions as early as possible and catch all exceptions as late as possible–are equally wrong. The moderate position is to catch each exception at the point where it is best dealt with. Sometimes this is the top or the bottom of the call stack, but more often it’s somewhere in between.

Exceptions are not an encapsulation violation. They are part of the contract of a method. If they expose implementation details, then the exception should be changed to a different (but still checked) exception that does not expose implementation details. But under no circumstances should you wish away that uncontrollable environmental problems such as I/O issues.

The web browser example is a good one, but it does not indicate what you think it does. For instance, suppose a web browser gets an UnknownHostException. That should be dealt with, either with a retry or by alerting the user. The alert to the user, if that’s the response chosen, should be specific to the problem. It requires a very specific set of actions in the browser’s GUI. It should not be delegated to a generic error handler somewhere close to the top of the stack or, worse yet, allowed to bubble up to main() and shut down the browser. Java is doing programmers a favor by indicating where these unpredictable environmental problems can arise, and it is doing users a favor by making it harder for programmers to pretend these problems won’t happen.


Inceptor Says: 
April 20th, 2010 at 7:10 pm
If, by definition, an exception is a signal not defined in the protocol (the interface),
including the exception in the protocol (a “checked exception”) would make it … a non-exception …

Checked exceptions simply expose implementation details.
Don’t use ‘em.


Andrew Thompson (lordpixel) Says: 
April 20th, 2010 at 10:11 pm
Exceptions are absolutely a part of the API of a program. Exceptions are not signals, they are fully developed objects with state and methods which are just as much a part of the API as the parameters and return values of methods. Interfaces should declare what exceptions are thrown if normal completion and return is not possible.

Nor must exceptions of any kind necessarily leak implementation details. Here’s an example of a horrible exception that leaks implementation details like a sieve because the error codes are completely vendor specific SQLException.getErrorCode(). Here’s Spring’s take on the same concept DataAccessException. Either can be used to recover from errors like deadlock – a common, predictable, recoverable error condition arising from environmental conditions outside of the project’s control, but SQLException is horribly vendor specific whereas DataAccessException doesn’t even expose whether a database is in use or not. From Java 6 onward you can see they’ve started to rehabilitate SQLException by adding DataAccessException subclasses to it.

In the SQLException/DataAccessException example it happens that the poorly designed exception is the checked Exception and the better designed one is a RuntimeException. But if the opposite were true, it wouldn’t change which exception has the better API overall. Whether an exception exposes an implementation detail depends entirely on whether it is well designed, not whether it is checked.

Modern programs are many layers deep. Applications call locally written libraries that call vendor libraries that call platform code. Each layer should be making the following decision about errors:

(i) can I handle this error at this level in the code

(ii) is it appropriate to pass the error to my caller, i.e. might my caller be able to handle it, or should I not throw it as is because i will be leaking an implementation detail

(iii) so alternately should I wrap the exception in another exception that my caller can understand – communicating the problem without leaking the implementation details

Again, it doesn’t fundamentally matter whether these exceptions are checked. A careful programmer could in theory consider every exception thrown by every method called and choose to catch it, declare it in the throws clause or wrap it appropriately whether it is checked or not.

But that’s theory – in practice if everything is a RuntimeException several things occur

The compiler isn’t able to tell the programmer which exceptions to focus on because they might be recoverable.
The compiler isn’t able to check the exception is handled on all code paths in a method for you, so you get subtle corner cases where you don’t handle the except even though you intended to.
Since most programmers aren’t dedicated enough to declare RuntimeExceptions in the throws clause, there’s no way for a programmer 2 layers or more above to know what the possible set of RuntimeExceptions thrown is unless they have access to and can read all of the code. The API is incomplete – its error conditions are unspecified. By hiding what is thrown, the programmer has little choice: catch everything, let everything go or guess the set of RuntimeExceptions to catch and hope the implementation doesn’t change

Several posters seem to feel the goal is to let everything go out through every layer and reach a top level error handler, but a top level error handler is very generic and is there as a last resort, because it is better to have some handler for things and not just dump them to the console where no one is looking. Just throwing up a dialog or a line in a log file which reads ‘What you were trying to do didn’t work due to a FooException’ is a bare minimum, not the end goal for error handling. Convenient for programmers, yes, but infuriating for users.


GabeMc Says: 
April 21st, 2010 at 10:43 pm
I have to disagree. The issue with throws is that the method signature changes. All inherited classes (including ones that you may not own), must change their code to handle exceptions which (even in subclasses) may never be thrown. It becomes particularly annoying when you have to waste code catching errors you know will never be called.


Troy Says: 
April 22nd, 2010 at 10:18 am
-1
>>Checked exceptions complicate the scenario a bit, because they force you to add catch clauses in places where you may not
>>be ready to handle an error. This is false.
Actually it is not false you assume that you can change the signature of your method to include a throws statement you have no idea how much code this can break in a project of real scale not something you hack by yourself for fun. A lot of the code you deal with you have no control over and can not force a change. A signature is a contract the throws clause is part of that contract you can not change it on a whim it might be defined by third parties or break to many other peoples code. So yes you are forced to catch that checked exceptions and yes you usually do not have enough knowledge in that point of the code to properly handle the exception so you usually log it or re throw it wrapped up as a Runtime exception. Only someone who has never worked on a big java project could say any different.

Checked exception are not composable and even though they espouse a more pure view (very much like Haskell monads) of the world where certain things should not compose. It is not a very practical way to look at things when you just need to to get things done.
You are stuck with a current system you need to extend its capabilities quickly within a deadline your customer could care less about your puritan views. Practicality beats purity.

Checked exceptions are definitely a failed experiements no other language has bothered to steal them if they were such a great
feature other languages would be imitating them.

Even Monads have at least some fans they even put Monads into VB.NET

Troy


Bruce Eckel Says: 
April 23rd, 2010 at 10:02 am
Cedric Says: “Checked exceptions are an absolute requirement to produce robust code.”

I’m pretty sure this says that no language without checked exceptions can produce robust code. So if anyone can find a counterexample, all of the arguments by that poster become questionable. (Perhaps he was being ironic or sarcastic and I missed it).

Here’s what Anders told me about why he left checked exceptions out of C#: they don’t scale. They seem like a good idea on the small scale, but they get very messy when things scale up (an idea which other commenters here seem to support). He told me that he wouldn’t exclude the possibility of including them at some later point if it makes sense (but that was years ago, regarding C# 1.0 if I remember), which sounds like the same attitude that Martin Odersky took with Scala.

The culture of Java is that nothing is ever removed. For that matter, nothing is ever acknowledged to be a mistake, and I think that does damage — not to language designers, who are smart enough not to repeat a mistake, but to programmers, especially those new to the profession, who see something and assume that because it is in the language it must be right. That was the reason I spent time researching the topic and making the arguments that I did in Thinking in Java (not just for checked exceptions, but for numerous other topics as well): I find that people are better programmers when they understand the imperfections of their language — they don’t spend time thinking “there must be some way to do this ‘right,’ because no one would make such a mistake in such a heavily-hyped programming language.” Instead, they see a tangled mess of (for example) checked exceptions and think “checked exceptions, right, interesting concept, but doesn’t always work out so well.”

So nothing gets removed, and most of this argument is thus not that important. Checked exceptions will always be in Java, and most of the people I know who’ve gotten tired of this and other mistakes that are bombastically defended (and everyone has to admit there are inarguably obvious ones like AWT and the first collection classes — the Java designers never to my knowledge apologized for these, but sometimes they replaced them, and maybe the addition of the “wrapping RuntimeException” is another one of those non-apologies), those people have just moved on, staying with the JVM but leaving Java, at least as much as they can. That’s probably the greatest thing the JVM has given us: choice, or at least the possibility of choice. When you outgrow Java, you don’t have to throw away everything you’ve learned or all the code you and everyone else has written. You can move on to Scala or Groovy or JRuby or Jython, etc., and get the best of all worlds.

And if you really, really love checked exceptions and think that no robust code can be written without them, then Java is the language for you and there’s no need for you to move on, and I can pretty much guarantee that your checked exceptions will never leave the language — it’s not in the culture. But if you are determined that everyone else must believe this and never, ever, wrap a checked exception in a RuntimeException, then you might have your work cut out for you. There are a lot of well-reasoned comments on this post alone that suggest that the argument is not as clear-cut as you might like to think.

(And a clarification for one or two posters who seem to have misunderstood, thinking I don’t like exceptions: a single, unified error handling mechanism is, I believe, very important if not essential. Thus, I think exceptions are great. It’s the CHECKED exceptions that I think have a lot of problems).


Elliotte Rusty Harold Says: 
April 26th, 2010 at 2:20 pm
This conversation made me take another look at some Python scripts I use on an almost daily basis (not written by me) and you know what I realized? They are far less robust in practice than the Java code written in the same environment. The Python scripts routinely die with an unhelpful stack trace as a result of bad user input and being run from the wrong directories. They are far too trusting of external data sources; and when they fail they are much less helpful to the end user than Java tools that fail in a similar situation. I strongly suspect the developers who wrote these programs (some in daily use by thousands of people) simply did not pay sufficient attention to error handling. I can’t help but think that if Python used checked exceptions and forced Python programmers to consider the possibility of bad input, then these programs would be more robust. I don’t know if the I/O errors could be corrected in all cases, but at least I wouldn’t see so many hard crashes.


Kaj Kandler Says: 
April 28th, 2010 at 10:41 am
I can see both sides of the issue. So let me add the things I like about checked exceptions, that are going missing if one uses only RuntimeExceptions:

* Exceptions tell me what can happen, they are documentation (and documentation that automated tools, like the compiler can work with). If that documentation is going missing (and comment only documentation is not a substitute, because it might not be up to date anymore) I don’t know what to look out for.
* Exceptions can and should carry the context of the exception, so I can produce messages for humans (internationalized). I.e. the IOException should carry a cause like “no read permission” and the (absolute) path it happened to (if a file).

If I let unknown runtime exceptions bubble up multiple layers then I have lost context, and a potentially treatable exception becomes untreatable for just that reason.

This becomes especially important if I write against libraries and APIs. If Exceptions are undocumented, then it is a pain to determine what to handle and how. If they are undocumented and changing over time (new release), how will I be reasonably sure that my program still works with the new version?

From where I stand neither extreme is a solution. I think we need to document exceptional behavior and make sure it brings with it the context that is needed to understand the specifics of the exception. Error handling is part of programming. So I’d like to see some solution to the dilemma where an Exception is part of the documented API but can be handled more flexible. For example Interfaces could include mechanisms that allow the Interface to catch all exceptions and translate them to a common type or delegate to a specific handler. That way an implementation could throw exceptions that the Interface designer did not foresee (because they are specific to the implementation) and the user of the interface could configure if he wants to deal with the implementation specific things or not.


Ivan Saorin Says: 
April 28th, 2010 at 6:03 pm
I think CHECKED exception is overused in general even at JDK level, but it is not a bad thing. I guess I can deal with JDK. The problem arise from not being clear enough on their use: a not so clear guideline from sun.

This is my actual strategy.

RULE #1 – Never, ever rethrow an exception of the same type of the original one. If you are doing this you are probably logging and rethrowing: that is really a bad attitude.

RULE #2 – Never catch a superclass of a given Exception. The reason is simple: let’s suppose we have a RootException and a WrongBalanceException that extends the former, we release version one of the library to the masses. Eventually some of the users will catch RootException. Now we will introduce a brand new FileValidationFailedException. You can see how the old client code could catch even the new exception without evidence: it should not compile at all as the semantic of the new exception could be totally different.

RULE #3 – Your application must have some “low level” code: the code that interacts with jdk and thirdy party libraries. Here the checked exception is the way to go. catch what make sense and wrap other conditions around RuntimeExceptions wrappers. You will end up having managed the exceptions or having them wrapped: either case are good. There is one notable “exception” to this: the one or two missing cases in which your “high level” code need to know and do something different in that case wrap the low level exception inside your own HighLevel checked exception.

RULE #4 – Your wrapper shoud do a kindness to the world and accept two different messages: one is for the end user and one is for the log file. The first is i18n while the latter is in english. Even if your locale is english this make sense: never show to the end user information that should be logged and viceversa.

The sad thing here is that even following the above rules in your project you will end up with some newbie following every possible antipattern 

What do you think about the rules? They seems to do a good job inside a quite big project.


Kjetil Valstadsve Says: 
May 2nd, 2010 at 7:05 am
Seems like my blog on exceptions from the future got automatically tracked here. It’s a bit stream-of-consciousness, but my main point is that you can’t predict the future. Java, on the other hand, is effectively handing out future prediction wands to everybody, and suggesting that their usage is mandatory. Obviously, there were good intentions to make Java software generally robust, but 15 years later I can’t really see that checked-ness of exceptions have contributed to solid facts on the ground here. Rather, I think the exception mechanism in itself isn’t being used effectively, maybe because the compiler support has given us a false sense of security. Lots of efforts have gone into “handling” exceptions that will never occur, and lots of actual errors have gone unhandled because neither the compiler, nor anyone else, could have predicted the exceptions BY TYPE.

I’ve been to Elliottes blog before and labored this point. I won’t spend so much effort here this time 


Eric S Says: 
September 11th, 2010 at 1:03 am
People continue to repeat Anders’ comment about checked exceptions not scaling, though Gosling debunked this way back in 2003. I’ve worked on large Java systems and never seen this problem either. It only happens if programmers are using exceptions incorrectly, by passing all exceptions up to some top level by sticking them on the throws class without regard for whether they are exposing implemention details.

Here’s the Gosling interview: http://www.artima.com/intv/solidP.html It’s funny, in this same article, he pretty much covered everything that has just been discussed here. There’s nothing new here. Why do we have to keep having this same argument? Personally I blame it on Java not having come with clear enough instructions about how to use exceptions properly; the arguments and explanations appeared after usage in the wild was already all over the place, and the seeds of confusion implanted in the culture.


Eddie Says: 
July 20th, 2011 at 4:04 pm

I think the ultimate solution to checked/unchecked will be found in some new language that will basically choose Java style checked + unchecked exceptions but with a significantly different twist, including a lot of syntactic sugar to solve the many valid points people have brought up about how annoying it can be to handle checked Exceptions. Things such as:

1) Automatic exception wrapping so exceptions you don’t want to handle can bubble up without being exposed as the base exception they are. If you are a security 3rd party library and you fail because your configuration caused you to throw a MalformedURLException, you want to throw a SecurityConfigurationException that wraps the other so the programmer making use of your library has a proper abstraction.
1a) Maybe something like try {} catch {} finally {} rethrows XXX where any Exception not explicitly caught is automatically wrapped as XXX, which can itself be checked or unchecked. Then you declare that this method throws XXX, and not whatever set of Exceptions could be wrapped by it, from that code block.
2) Interface versioning so you can change an interface, changing what Exceptions are or are not declared to be thrown, with ways of handling mismatching interface versions. Maybe automatic wrapping can solve this problem.
3) Perhaps the ability to mark a given Exception instance as checked or unchecked in a method’s declaration or code, so you can declaratively note whether something is expected to be caught or not. Maybe an annotation.
4) More things.  

I disagree with many of Java’s choices with regards to what is a checked exception and what is not, and in both directions. I find, for example, that my code is more stable when I catch NumberFormatException, as this is almost always NOT a programming bug, but a bad input that needs to be handled. And I have found it appropriate in a very small number of places to catch Throwable, even if to log and rethrow, which as a general practice is not great but in the right place can provide invaluable information if you cannot depend on other software layers to report things appropriately. Also, “software should die on an Error being thrown” is not always true. If you get an out of memory error because the current request requires you to allocate an object that is too big to fit in memory, then you fail that request but don’t crash the program which is otherwise (in my experience) handling things just fine. It just got an invalid request. This depends on context and on whether or not one failed request means others can continue. How independent are the requests coming in? A programmer knows. An language runtime does not.


Alaric Snell-Pym says:
April 26, 2010 at 1:28 pm
Yes. It’s a common misconception that one has to handle exceptions. People look at the return value and exception signature of a function as one thing – and decide how to handle the result of that call.

Exceptions should only be caught in three places, off of the top of my head:

1) Where you can do something useful about the exception (eg, try something else)

2) Where you can’t let the failure rise any further (eg, you’re looping through a number of entries in a queue, and if one fails you want to log that and start on the next, rather than giving up on the whole queue)

3) Where you’re protecting the user from the grungy details. This one is easy to get wrong. Yeah, the QA team complain that your app gives a scary error message full of stacktrace. So catch that exception, pop up a little dialog box with a single line of error message in it – but then have a button that opens up your mail client with an email to support@mycompany.com with the backtrace in it, or equivalent.


Reply
david says:
April 26, 2010 at 1:44 pm
Agreed on all of these. One additional case where it’s sometimes necessary: When you’re doing something funny with control flow. e.g. because your code is written in CPS, or because you need to pass things between threads. e.g. the RabbitMQ Java client runs most of its handling code in a MainLoop thread, and when things go wrong it needs to transmit the exceptions to the calling threads rather than just have that one die.



Commits for litesoft/trunk/Documents/CheckedVsUncheckedExceptions.txt

Diff revisions: vs.
Revision Author Commited Message
608 GeorgeS picture GeorgeS Sat 10 Mar, 2012 18:32:36 +0000

Saving