When and How to Use Exception Handling

When and how should I use exception handling?

Here's quite comprehensive guide on exceptions that I think is a Must Read:

Exceptions and error handling - C++ FAQ or C++ FAQ lite

As a general rule of thumb, throw an exception when your program can identify an external problem that prevents execution. If you receive data from the server and that data is invalid, throw an exception. Out of disk space? Throw an exception. Cosmic rays prevent you from querying the database? Throw an exception. But if you get some invalid data from inside your very own program - don't throw an exception. If your problem comes from your own bad code, it's better to use ASSERTs to guard against it. Exception handling is needed to identify problems that program cannot handle and tell them about the user, because user can handle them. But bugs in your program are not something the user can handle, so program crashing will tell not much less than "Value of answer_to_life_and_universe_and_everything is not 42! This should never happen!!!!11" exception.

Catch an exception where you can do something useful with it, like, display a message box. I prefer to catch an exception once inside a function that somehow handles user input. For example, user presses button "Annihilate all hunams", and inside annihilateAllHunamsClicked() function there's a try...catch block to say "I can't". Even though annihilation of hunamkind is a complex operation that requires calling dozens and dozens of functions, there is only one try...catch, because for a user it's an atomic operation - one button click. Exception checks in every function are redundant and ugly.

Also, I can't recommend enough getting familiar with RAII - that is, to make sure that all data that is initialized is destroyed automatically. And that can be achieved by initializing as much as possible on stack, and when you need to initialize something on heap, use some kind of smart pointer. Everything initialized on the stack will be destroyed automatically when an exception is thrown. If you use C-style dumb pointers, you risk memory leak when an exception is thrown, because there is noone to clean them up upon exception (sure, you can use C-style pointers as members of your class, but make sure they are taken care of in destructor).

Why do we need exception handling?

Suppose you have func1 calling func2 with some input.

Now, suppose func2 fails for some reason.

Your suggestion is to handle the failure within func2, and then return to func1.

How will func1 "know" what error (if any) has occurred in func2 and how to proceed from that point?

The first solution that comes to mind is an error-code that func2 will return, where typically, a zero value will represent "OK", and each of the other (non-zero) values will represent a specific error that has occurred.

The problem with this mechanism is that it limits your flexibility in adding / handling new error-codes.

With the exception mechanism, you have a generic Exception object, which can be extended to any specific type of exception. In a way, it is similar to an error-code, but it can contain more information (for example, an error-message string).

You can still argue of course, "well, what's the try/catch for then? why not simply return this object?".

Fortunately, this question has already been answered here in great detail:

In C++ what are the benefits of using exceptions and try / catch instead of just returning an error code?

In general, there are two main advantages for exceptions over error-codes, both of which are different aspects of correct coding:

  1. With an exception, the programmer must either handle it or throw it "upwards", whereas with an error-code, the programmer can mistakenly ignore it.

  2. With the exception mechanism you can write your code much "cleaner" and have everything "automatically handled", wheres with error-codes you are obliged to implement a "tedious" switch/case, possibly in every function "up the call-stack".

How does exception handling work internally in Java?

If ExceptionType is class, shouldn't name be reference to an object? Even if it is a reference, since we haven't created any object, what exactly does it contain?

The simple answer to your question / misunderstanding is that catching an exception does NOT create an exception object. Rather, the exception object was created earlier.

When you do this:

 throw new SomeException("message");

the new is explicitly creating an exception object.

When you do this:

SomeClass foo = null;
foo.someMethod();

the JVM will create a NullPointerException object.

In either case, it will be those objects that are assigned to the variable in the catch clause; name in your example.


This also indirectly explains something else. When you call printStackTrace() on an exception object, it will (apparently) print the stack trace for the point at which the exception was thrown.

How does it manage this?

Well actually, what I said above was slightly incorrect. What it is actually printing is the stacktrace for the point at which the exception object was created! (The two points are usually the same, but not always.)

What actually happens is that when the exception object is created (by new, by the JVM, or by native code) the constructor for Throwable (the ancestor class of all exception classes) calls a method called fillInStackTrace(). This in turn calls an internal method that populates an array with the stack frame information for the current call context.

How using try catch for exception handling is best practice

My exception-handling strategy is:

  • To catch all unhandled exceptions by hooking to the Application.ThreadException event, then decide:

    • For a UI application: to pop it to the user with an apology message (WinForms)
    • For a Service or a Console application: log it to a file (service or console)

Then I always enclose every piece of code that is run externally in try/catch :

  • All events fired by the WinForms infrastructure (Load, Click, SelectedChanged...)
  • All events fired by third party components

Then I enclose in 'try/catch'

  • All the operations that I know might not work all the time (IO operations, calculations with a potential zero division...). In such a case, I throw a new ApplicationException("custom message", innerException) to keep track of what really happened

Additionally, I try my best to sort exceptions correctly. There are exceptions which:

  • need to be shown to the user immediately

  • require some extra processing to put things together when they happen to avoid cascading problems (ie: put .EndUpdate in the finally section during a TreeView fill)

  • the user does not care, but it is important to know what happened. So I always log them:

  • In the event log

  • or in a .log file on the disk

It is a good practice to design some static methods to handle exceptions in the application top level error handlers.

I also force myself to try to:

  • Remember ALL exceptions are bubbled up to the top level. It is not necessary to put exception handlers everywhere.
  • Reusable or deep called functions does not need to display or log exceptions : they are either bubbled up automatically or rethrown with some custom messages in my exception handlers.

So finally:

Bad:

// DON'T DO THIS; ITS BAD
try
{
...
}
catch
{
// only air...
}

Useless:

// DON'T DO THIS; IT'S USELESS
try
{
...
}
catch(Exception ex)
{
throw ex;
}

Having a try finally without a catch is perfectly valid:

try
{
listView1.BeginUpdate();

// If an exception occurs in the following code, then the finally will be executed
// and the exception will be thrown
...
}
finally
{
// I WANT THIS CODE TO RUN EVENTUALLY REGARDLESS AN EXCEPTION OCCURRED OR NOT
listView1.EndUpdate();
}

What I do at the top level:

// i.e When the user clicks on a button
try
{
...
}
catch(Exception ex)
{
ex.Log(); // Log exception

-- OR --

ex.Log().Display(); // Log exception, then show it to the user with apologies...
}

What I do in some called functions:

// Calculation module
try
{
...
}
catch(Exception ex)
{
// Add useful information to the exception
throw new ApplicationException("Something wrong happened in the calculation module:", ex);
}

// IO module
try
{
...
}
catch(Exception ex)
{
throw new ApplicationException(string.Format("I cannot write the file {0} to {1}", fileName, directoryName), ex);
}

There is a lot to do with exception handling (Custom Exceptions) but those rules that I try to keep in mind are enough for the simple applications I do.

Here is an example of extensions methods to handle caught exceptions a comfortable way. They are implemented in a way they can be chained together, and it is very easy to add your own caught exception processing.

// Usage:

try
{
// boom
}
catch(Exception ex)
{
// Only log exception
ex.Log();

-- OR --

// Only display exception
ex.Display();

-- OR --

// Log, then display exception
ex.Log().Display();

-- OR --

// Add some user-friendly message to an exception
new ApplicationException("Unable to calculate !", ex).Log().Display();
}

// Extension methods

internal static Exception Log(this Exception ex)
{
File.AppendAllText("CaughtExceptions" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", DateTime.Now.ToString("HH:mm:ss") + ": " + ex.Message + "\n" + ex.ToString() + "\n");
return ex;
}

internal static Exception Display(this Exception ex, string msg = null, MessageBoxImage img = MessageBoxImage.Error)
{
MessageBox.Show(msg ?? ex.Message, "", MessageBoxButton.OK, img);
return ex;
}

Where should I put my exception handling in Spring MVC?

Unless you can recover from an error condition, you'll have to let your exceptions pop all the way up to the controller, so that you can convert them into HTTP errors and signal that error back to the client.

Since (e.g.) "invalid input" will have to get back to the client as a 400 Bad Request HTTP status code, it's obvious that only the Spring MVC controller is able to do that.

That's why it may be a good idea to define error handling methods for different kinds of errors and map exceptions to status codes. An example of such a mapping would be:

  • IllegalArgumentException -> 400 Bad Request
  • IllegalStateException -> 503 Service Unavailable
  • AuthenticationException -> 401 Unauthorized
  • AccessDeniedException|SecurityException -> 403 Forbidden
  • UnsupportedOperationException -> 501 Not Implemented
  • Throwable (anything else) -> 500 Internal Server Error

The service layer should only handle recoverable exceptions and it should translate (wrap) low-level exceptions into a coherent set of well-defined exceptions (e.g. catch (FileNotFoundException e) -> throw new IllegalStateException(e)).

So it doesn't become useless. Besides, this layer should contain all the "business logic" and let the Spring MVC (or whatever web framework) controller focus only on HTTP stuff.

Why should I use exception handling in php?

Exceptions allow you to distinguish between different types of errors, and is also great for routing. For example...

class Application
{
public function run()
{
try {
// Start her up!!
} catch (Exception $e) {
// If Ajax request, send back status and message
if ($this->getRequest()->isAjax()) {
return Application_Json::encode(array(
'status' => 'error',
'msg' => $e->getMessage());
}

// ...otherwise, just throw error
throw $e;
}
}
}

The thrown exception can then be handled by a custom error handler.

Since PHP is a loosely typed language, you might need to ensure that only strings are passed as arguments to a class method. For example...

class StringsOnly
{
public function onlyPassStringToThisMethod($string)
{
if (!is_string($string)) {
throw new InvalidArgumentException('$string is definitely not a string');
}

// Cool string manipulation...

return $this;
}
}

...or if you need to handle different types of exceptions in different ways.

class DifferentExceptionsForDifferentFolks
{
public function catchMeIfYouCan()
{
try {
$this->flyForFree();
} catch (CantFlyForFreeException $e) {
$this->alertAuthorities();
return 'Sorry, you can\'t fly for free dude. It just don\'t work that way!';
} catch (DbException $e) {
// Get DB debug info
$this->logDbDebugInfo();
return 'Could not access database. What did you mess up this time?';
} catch (Exception $e) {
$this->logMiscException($e);
return 'I catch all exceptions for which you did not account!';
}
}
}

If using transactions in something like Zend Framework:

class CreditCardController extends Zend_Controller_Action
{
public function buyforgirlfriendAction()
{
try {
$this->getDb()->beginTransaction();

$this->insertGift($giftName, $giftPrice, $giftWowFactor);

$this->getDb()->commit();
} catch (Exception $e) {
// Error encountered, rollback changes
$this->getDb()->rollBack();

// Re-throw exception, allow ErrorController forward
throw $e;
}
}
}

Why should I use Exception handlings in Java?

It's three questions, but it's not like that's the first time that's happened here. :-)

  1. Yes, you must handle them or declare them, because they're checked exceptions. The reason you must do that is so that the code calling your code knows the ways in which your code may fail (because you've declared the exceptions it can throw).

  2. That snippet is very simple, so the separation and benefit aren't all that clear. But consider opening two streams, copying from one to another, with transformation code (including calls to subordinate methods). You end up with a method body with 10-20 statements in it. Instead of every I/O statement having to check whether it worked or not, you just write your logic wrapped in an IOException handler, knowing that any I/O exceptions will jump out of the main logic into the handler.

  3. It depends on what kind of program you're writing, but in general you handle exceptions at the most appropriate level, which is typically at multiple levels in your program. The outermost level, which is only to deal with really, really unusual, unrecoverable exceptions, would either just let the default handling do what it does, or use a catch-all handler that does something similar but might (attempt to) record the failure elsewhere (like a log file) as well:

    public class MyProgram {
    public static final void main(String[] args) {
    try {
    // Run...
    }
    catch (Throwable t) {
    // Handle the fact that something went wrong here, if you can
    // Usually this would be only for really, really unusual errors,
    // otherwise you would have handled them earlier
    }
    }
    }

To underscore the point in #2, consider two process methods, one in Java with exceptions, and the other in a hypothetical Java-like language that doesn't have exceptions:

The Java one:

private void process() {
try ( // <== Main logic
Reader fr = new FileReader(this.sourceFileName); // <== Main logic
BufferedReader br = new BufferedReader(fr); // <== Main logic
Writer fw = new FileWriter(this.destFileName); // <== Main logic
BufferedWriter bw = new BufferedWriter(fw) // <== Main logic
) { // <== Main logic
String line; // <== Main logic
while ((line = br.readLine()) != null) { // <== Main logic
if (shouldIncludeLine(line)) { // <== Main logic
line = transformLine(line); // <== Main logic
bw.write(line); // <== Main logic
bw.newLine(); // <== Main logic
} // <== Main logic
} // <== Main logic
}
catch (FileNotFoundException fnfe) { // <== Error handling
// Couldn't find a file // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
catch (IOException ioe) { // <== Error handling
// I/O error // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
catch (Exception e) { // <== Error handling
// Something else went wrong // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
}

The hypothetical Java-like language without exceptions one:

// THIS IS FAKE, PSEUDO-JAVA
private Errors process() {
Reader fr = new FileReader(this.sourceFileName); // <== Main logic
if (fr == null) { // <== Error handling
return Errors.CantOpenSource; // <== Error handling
} // <== Error handling
BufferedReader br = new BufferedReader(fr); // <== Main logic

Writer fw = new FileWriter(this.destFileName); // <== Main logic
if (fw == null) { // <== Error handling
br.close(); // <== Error handling
return Errors.CantOpenDest; // <== Error handling
} // <== Error handling
BufferedWriter bw = new BufferedWriter(fw) // <== Main logic

String line; // <== Main logic
while ((line = br.readLine()) != IO.END_OF_FILE) { // <== Main logic
if (line == null) { // <== Error handling
br.close(); // <== Error handling
bw.close(); // <== Error handling
return Errors.CantRead; // <== Error handling
}
if (shouldIncludeLine(line)) { // <== Main logic
line = transformLine(line); // <== Main logic
if (bw.write(line) == -1 || bw.newLine() == -1) { // <== Main logic (plus some error handling)
br.close(); // <== Error handling
bw.close(); // <== Error handling
return Errors.CantWrite; // <== Error handling
}
}
}

bw.close();
br.close();
return Errors.Success;
}

Notice:

  • How the main logic is littered with error handling, making it harder to read and follow.
  • Special "error" return values are necessary for any method that might possibly have some kind of failure mode. We had to add one to process, and then we check for null from new FileReader and such, and check for -1 from read and write ops, etc.

If you're interested, here's a full version of the Java program vs. the full version of the not-really-Java program:

Java:

import java.io.*;

public class Example
{
private String sourceFileName;
private String destFileName;

public static void main (String[] args) throws java.lang.Exception
{
try {
new Example(args[0], args[1]).process();
}
catch (ArrayIndexOutOfBoundsException npe) {
// This is a bit of an exaggeration, I'd check in advance, since the user not
// supplying arguments isn't really an "exceptional" condition.
System.out.println("Usage: java Example [source file name] [dest file name]");
}
}

public Example(String src, String dest) {
// Similar, these checks would probably be assertions, but I'm making a point...
if (src == null || src.length() == 0) {
throw new IllegalArgumentException("src must be non-null and non-blank");
}
if (dest == null || dest.length() == 0) {
throw new IllegalArgumentException("dest must be non-null and non-blank");
}
this.sourceFileName = src;
this.destFileName = dest;
}

private void process() {
try ( // <== Main logic
Reader fr = new FileReader(this.sourceFileName); // <== Main logic
BufferedReader br = new BufferedReader(fr); // <== Main logic
Writer fw = new FileWriter(this.destFileName); // <== Main logic
BufferedWriter bw = new BufferedWriter(fw) // <== Main logic
) { // <== Main logic
String line; // <== Main logic
while ((line = br.readLine()) != null) { // <== Main logic
if (shouldIncludeLine(line)) { // <== Main logic
line = transformLine(line); // <== Main logic
bw.write(line); // <== Main logic
bw.newLine(); // <== Main logic
} // <== Main logic
} // <== Main logic
}
catch (FileNotFoundException fnfe) { // <== Error handling
// Couldn't find a file // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
catch (IOException ioe) { // <== Error handling
// I/O error // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
catch (Exception e) { // <== Error handling
// Something else went wrong // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
}

private boolean shouldIncludeLine(String line) {
return line.length() != 0;
}

private String transformLine(String line) {
return line.toUpperCase();
}
}

The hypothetical Java-like language without exceptions one:

// THIS IS FAKE, PSEUDO-JAVA WITHOUT EXCEPTIONS, IT ISN'T REAL
import java.io.*;

public class Example
{
private String sourceFileName;
private String destFileName;

private enum Errors {
Success,
CantOpenSource,
CantOpenDest,
CantRead,
CantWrite
}

public static void main (String[] args) throws java.lang.Exception
{
if (args.length < 2) {
System.out.println("Usage: java Example [source file name] [dest file name]");
}
if (args[0] == null || args[0].length() == 0) {
throw new IllegalArgumentException("src must be non-null and non-blank");
}
if (args[1] == null || args[1].length() == 0) {
throw new IllegalArgumentException("dest must be non-null and non-blank");
}
switch (new Example(args[0], args[1]).process()) {
case Errors.CantOpenSource:
// Handle it
break;
case Errors.CantOpenDest:
// Handle it
break;
case Errors.CantRead:
// Handle it
break;
case Errors.CantWrite:
// Handle it
break;
}
}

public Example(String src, String dest) {
// Not how now this constructor is trusting that it is called with valid arguments
this.sourceFileName = src;
this.destFileName = dest;
}

private Errors process() {
Reader fr = new FileReader(this.sourceFileName); // <== Main logic
if (fr == null) { // <== Error handling
return Errors.CantOpenSource; // <== Error handling
} // <== Error handling
BufferedReader br = new BufferedReader(fr); // <== Main logic

Writer fw = new FileWriter(this.destFileName); // <== Main logic
if (fw == null) { // <== Error handling
br.close(); // <== Error handling
return Errors.CantOpenDest; // <== Error handling
} // <== Error handling
BufferedWriter bw = new BufferedWriter(fw) // <== Main logic

String line; // <== Main logic
while ((line = br.readLine()) != IO.END_OF_FILE) { // <== Main logic
if (line == null) { // <== Error handling
br.close(); // <== Error handling
bw.close(); // <== Error handling
return Errors.CantRead; // <== Error handling
}
if (shouldIncludeLine(line)) { // <== Main logic
line = transformLine(line); // <== Main logic
if (bw.write(line) == -1 || bw.newLine() == -1) { // <== Main logic (plus some error handling)
br.close(); // <== Error handling
bw.close(); // <== Error handling
return Errors.CantWrite; // <== Error handling
}
}
}

bw.close();
br.close();
return Errors.Success;
}

private boolean shouldIncludeLine(String line) {
return line.length() != 0;
}

private String transformLine(String line) {
return line.toUpperCase();
}
}

Should I handle exception with Closable.use{...} in Kotlin?

This line

 BufferedReader(FileReader("test.file")).use { return it.readLine() }

is not safe. Reading and closing the reader can both throw IOExceptions, which are not RuntimeExceptions (caused by programming errors). That means leaving them uncaught exposes your app to crashing from things outside your control.

Since Kotlin doesn't have checked exceptions, the compiler won't warn you about this. To do this safely, you need to wrap it in try/catch. And if you want to handle read errors differently than close errors, you either need to have inner and outer try/catch statements:

try { 
BufferedReader(FileReader("test.file")).use {
try {
return it.readLine()
catch (e: IOException) {
println("Failed to read line")
}
}
} catch (e: IOException) {
println("Failed to close reader")
}

or wrap the whole thing and extract any suppressed exceptions, but then its cumbersome to distinguish between them:

try {
BufferedReader(FileReader("test.file")).use { return it.readLine() }
} catch (e: IOException) {
val throwables = listOf(e, *e.suppressed)
for (throwable in throwables)
println(throwable.message)
}


Related Topics



Leave a reply



Submit