1

This is a follow up question to this one.

It seems to be generally accepted that doing a broad 'catch (Exception)' is a bad idea.

The reasoning is typically something like 'you must handle the exception properly' and 'catch what you can handle' and a few other generic sounding arguments.

Those generic answer sound reasonable, but they don't really satisfy me.

Let me be concrete. Here's a typical bit of code which is supposed to be 'bad'.

try {
   ... do something...
} catch (Exception e) {
   log(e); //leave a trace for debugging
   return ...a value the context can deal with...
}

A sceptical mind can remain unconvinced that not handling the exception, (which will probably blow up the entire program), is necessarily a better outcome than handling it in this generic way.

So I would really like some specific and convincing example(s), with code snippet(s), of something bad that actually happens because of a supposedly too broad catch clause like the one above.

PS: one could think about this question in other languages than Java, but since I want specific examples, this is really about specific Exceptions that might be raised by a Java program and JRE.

PS2: I am specifically interested in examples of Exception that are in fact a subtype of java.lang.Exception and not the more broadly 'Throwable'. So that rules out stuff like 'OutOfMemoryError' as valid examples.

Community
  • 1
  • 1
Kris
  • 3,898
  • 1
  • 23
  • 32

3 Answers3

6

Catching a NullPointerException can result in the application stumbling onward oblivious to the fact that something it needed was not done. Later the application will fail again or behave abnormally because that previous operation did not complete, but it will be harder to figure out now.

Eating an exception within a transaction can result in the transaction not getting rolled back when it should have been. You could end up with inconsistent data.

Eating interruptedException:

public void run() {
    while (!Thread.currentThread().isInterrupted()) {
        try {
            doSomeWork();
            Thread.sleep();
        } catch (Exception e) {
        }
    }
}

If the thread gets interrupted while sleeping, the interrupted flag will get reset when the sleep method throws InterruptedException, since the catch doesn't restore the interrupt flag the while loop condition stays false and the thread doesn't exit.

Similarly, since InterruptedIOException is a subclass of IOException: if you have network IO code that only handles IOException then you can fail to restore the interrupt flag on and fail to detect that your thread has been interrupted.

Kris
  • 3,898
  • 1
  • 23
  • 32
Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
  • 6
    ... and by the time it blows up, there may have been damage to data... – Jon Skeet Jan 05 '16 at 20:39
  • `nerd alert` I've seen this type of exception crash a game server before because an individual abusing the source code created a bunch of null exceptions which eventually lagged up the server so much that it crashed. Real life example where the company in question lost mucho money. – Riley Carney Jan 05 '16 at 20:43
  • @Riley: ouch. running untrusted code on their servers? what could possibly go wrong? – Nathan Hughes Jan 05 '16 at 20:45
  • @NathanHughes haha exactly. Whoever coded it didn't think it'd be a problem because it was an exception that rarely came up with the login authorization server, and every case was eventually handled, but a infamous user created a program (I believe in python) which spammed it so the server couldn't keep up with authorizing every user and undoing the nulls, so it eventually crashed. I have no idea why he didn't just do it when he caught the exception, but I never saw the source code, so I didn't know the logic behind it. – Riley Carney Jan 05 '16 at 20:48
  • NullPointerException is a reasonable example. OutOfMemory error isn't (see https://docs.oracle.com/javase/7/docs/api/java/lang/OutOfMemoryError.html) as it is not a subtype of 'Exception' (but I admit my question may need a bit rephrasing to say I am precisely interested in catch (Exception) and not the even more broad 'catch Throwable'). – Kris Jan 05 '16 at 20:53
  • The best answer so far. NPE is compelling. I do tend to think of those as 'bug exceptions' which you probably shouldn't even ever have happen. But I'm really not so convinced that this means my program should 'just quit' while the user is running it (it's fine and desirable if it does that when I'm testing it of course, but when user is running, I'd probably prefer the program tries hard to keep working and logs some debug infos in a log file). – Kris Jan 05 '16 at 21:04
  • @Kris: definitely most things should get caught and handled somehow. just there's a benefit to the part that handles the exception being removed from the part that generates the exception. it's a matter of finding the right place. – Nathan Hughes Jan 05 '16 at 21:10
  • I knew about the 'InterrupedException' but its a good example :-) Still, probably not enough yet to really make me stop from writing catch (Exception e) -> log in a bunch of places. It is possible to find examples of things that go bad with too broad catch clauses, but there's certainly also examples where things went bad because people just don't catch and handle enough. Here is one: https://bugs.eclipse.org/bugs/show_bug.cgi?id=478225 I had to ask them twice to 'broaden' the catch to avoid Eclipse from blowing up. So what's worse? What's more likely to cause problems ... – Kris Jan 05 '16 at 21:48
  • Anecdotally, I've personally more often run into prorblems because some exception was left to propagate too far than cases where it was caught too early. But yeah, its about finding the right place :-) – Kris Jan 05 '16 at 21:49
0

The reason is you may want to handle different exceptions differently.

For example, in some applications I write I need to inform the user exactly what has gone wrong. If I just catch Exception I need to perform extra checks to distinguish between exceptions. If I catch specific exceptions I can easily do different things.

If I'm calling listFiles on a File, I might want to show a popup if a SecurityException occurs, but if a FileNotFoundException occurs I may want to open a FileChooser dialog.

EDIT: Now that I'm on a keyboard, I should also add that at times catch (Exception e) is good for the purposes of logging, but if you don't plan on handling it then you should always rethrow that exception. One man's trash is another's treasure as they say.

samczsun
  • 1,014
  • 6
  • 16
  • Yes, you may want to handle different exceptions differently. But that really is not a argument that handling it generically is worse than not handling it and let the program blow up. – Kris Jan 05 '16 at 20:55
  • Well, specifically, the subclass of `Exception`, `RuntimeException` is used to signal that something has happened and you can't recover from it. If you catch all `Exception`s then you've gone and caught all `RuntimeException`s too. `UnsupportedOperationException` extends `RuntimeException`, but you don't necessarily want to swallow that exception and wander on blindly. Same with `ArithmeticException` - you don't really want to proceed after you've gone and divided by zero. – samczsun Jan 05 '16 at 21:02
  • You can argue that these exceptions may not blow up your program, but I'd imagine if you put code in your program then it's there for a good reason. If the exception is flagged as `you can't recover from this`, then why would you try to recover from it? – samczsun Jan 05 '16 at 21:02
  • Also, one last point. We've based all our answers around the idea that you've caught it, and you do nothing with it. That's really what the whole idea against catching all Exceptions is about. If you do catch Exception and properly handle all the exceptions, there's nothing 'wrong' with it. It's just an alternative way of doing it. It's only when you catch and don't handle that you really threaten to blow up your program – samczsun Jan 05 '16 at 21:05
  • The case I really have in mind is that you catch it, log it, and return something that you expect the context can handle, e.g. a empty collection, or empty array or a null. So this is not 'wandering blindly' but doing two things: 1) leave trace in the log for later debuggin and 2) confine the failure to a 'controlled' context. If I let the exception 'fly' then it truly may wander on blindly as you probably have no idea when/if/where it may or may not be caught and handled. – Kris Jan 05 '16 at 21:30
  • "... you should always rethrow that exception..." I'd rather not. When its logged there's a trace already. retrow it, and if you keep using that pattern your logs will be bogged down with several copies of the same info. – Kris Jan 05 '16 at 21:52
  • In your case, if you catch it, possibly log it, **and** appropriately handle it (eg return a value you've either associated with `undefined` or `error` which you are expecting) then I see nothing wrong with it. In that situation there's also no point in rethrowing it. It's only when you don't handle it that the situation can spiral out of control. – samczsun Jan 05 '16 at 22:29
0

I'll turn that around and say that I think about the only time that an overly broad catch is appropriate is if the situation is "no matter what fails here, we're just quitting", like:

try {
   /* ... do something terribly important... */
} catch (Exception e) {
   System.err.println("We are totally screwed");
   e.printStackTrace();
   System.exit(1);
}
John Hascall
  • 9,176
  • 6
  • 48
  • 72
  • Actually, I totally disagree. Its more like I'd use it to say 'no matter what fails here... try your very best to keep on running'. That with the understanding also that 'Exception' doesn't truly catch everything like "catch Throwable" would, so its broad, yes, maybe too broad, but it could be broader still. Anyhow you didn't answer the question, I'm looking for a concrete example showing that catch Throwable is indeed 'too broad'. Basically, I want a good example to show me I really shouldn't do that... or else... – Kris Jan 05 '16 at 22:01
  • The answer by Nathan Hughes outlines several such scenarios. If you are in a "this is so important it must keep running 'no matter what'" scenario, then it is ever more critical to know the exact cause of the exception so that you can perform the correct remediation/mitigation for that exact situation. – John Hascall Jan 05 '16 at 23:01
  • Its not really 'no matter what'. Its more like its 'nicer' not to crash and have some bits not working than to just crash and burn so you have to restart the thing only to be booted out again. Cases where I've done this kind of thing is usually some methods where it is relatively easy to return a 'empty' value such as a empty collection, a null or whatnot. And I know that the program will be able to handle that (maybe some info is going to be missing or some function won't quite work, but this is really better than the whole thing falling flat on its ass. And sure, if I had another week... – Kris Jan 07 '16 at 00:26
  • ... maybe I could add the exact 25 catch clauses that I care about (how would I exactly know all the unexpected ways something might fail anyway, that isn't always easy?). Anyhoo... this question is really because I feel uncomfortable doing this 'bad' thing, but have not really been that convinced that its worse than the program crashing on my users in unexpected ways (PS: program in this case is Eclipse and it already crashes more than enough :-) – Kris Jan 07 '16 at 00:29
  • Certainly some software is written to a higher standard than others -- once upon a time I wrote software for an X-ray machine where a "blue screen of death" could literally mean death. – John Hascall Jan 07 '16 at 02:23