Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Try/Catch in every method of every class?

When we wrap a bunch of statements in a try/catch and one of these issues an exception, within the catch we have no way of knowing which of the statements caused the exception (the ex.stacktrace shows our current method (doit), its caller, its caller's caller, etc. but neither do1 or do2):

function doit() {
   try {
     do1();
     do2();
     [...]
   }
   catch (Exception ex) {
     // what failed?
   }
}

generally I've taken to wrapping all statements and rethrowing, sort of like:

private void do1() {
  try {
     // do whatever
  } catch(Exception e) {
     // write to my error log
     throw new Exception("do1: " + e.Message, e.InnerException);
  }
}

which leaves a trail of breadcrumbs in my log and makes the chain available for the upstream. The problem, of course, is that I have to wrap every method I write with this kind of code.

something tells me I'm being dumb about it. what is the right approach?

like image 352
ekkis Avatar asked Jun 28 '12 00:06

ekkis


People also ask

Should every method have try catch?

try/catch should usually be used sparingly - you should only catch an exception if either a) you can genuinely handle it (e.g. retrying) or b) it's at a "top level" for the application (e.g. the top level request handler for a server) and you're basically just stopping the whole application from stopping.

Can I have multiple try catch in a function?

You cannot have multiple try blocks with a single catch block.

Can we use try catch in class?

You can either handle it or you can't. If you can't handle it then you don't catch it.

Why you should not use try catch?

Without a try catch, you run the risk of encountering unhandled exceptions. Try catch statements aren't free in that they come with performance overhead. Like any language feature, try catches can be overused.


1 Answers

Ok, this is hard to get right because exception handling is a really really touchy subject and in the past people have fought religious wars over how to do this right.

First off: neither use an empty catch (try { ... } catch { ... }), nor catch(Exception ex). The sole purpose of Exception-derived classes is to give you rich information about the kind of exception which occured so you can do something meaningful in your exception handler (if a thread crashed restart it, if a db connection failed non-permanently try again, then fail, etc).

People tend to use a catch-all handler for the outermost part of their code to log uncaught exceptions and this is kind of OK, but in any case you should either prompt the user or rethrow the exception (using throw, not throw ex - there is a ton of discussion about this as well).

Basically you do not programmatically care about where the Exception occured at all. You can either handle it or you can't. If you can't handle it then you don't catch it.

Addendum: The most important reason for this "if you can do something about it, do so, otherwise dont you dare touch that exception" philosophy is that silently caught exceptions (whether logged or not) can lead to really hard-to-find bugs. Just pushing them out to a logfile might not be enough because in a live system you may not get the fully annotated stack trace (with line numbers and everything).

Addendum 2: Take for instance a textbox which expects an integer input. If the user supplies a string you cannot meaningfully process the input, maybe a conversion exception gets thrown, you catch that specific exception and reset the textbox to its old value and maybe inform the user about the erroneous input. Alternatively your program might either just die with an exception (bad design, you could recover from that exception) or silently go on showing the erroneous input, but still using the old value (bad design, the program is misleading).

like image 106
M.Stramm Avatar answered Oct 02 '22 11:10

M.Stramm