When to catch the Exception vs When to throw the Exceptions?

I have been coding in Java for a while now. But sometimes, I don't understand when I should throw the exception and when should I catch the exception. I am working on a project in which there are lot of methods. The hierarchy is something like this-

Method A will call Method B and Method B will call some Method C and Method C will call Method D and Method E.

So currently what I am doing is- I am throwing exceptions in all the methods and catching it in Method A and then logging as an error.

But I am not sure whether this will be the right way to do it? Or should I start catching exceptions in all the Methods. So that is why this confusion started in my- When should I catch the Exception vs When should I throw the exceptions. I know it's a silly question but somehow I am struggling to understand this major concept.

Can someone give me a detailed example of When to catch the Exception vs When to throw the Exceptions so that my concepts gets cleared on this? And in my case, should I keep on throwing the exception and then catch it in the main calling Method A?


Solution 1:

You should catch the exception when you are in the method that knows what to do.

For example, forget about how it actually works for the moment, let's say you are writing a library for opening and reading files.

So you have a class, say:

public class FileInputStream extends InputStream {
    public FileInputStream(String filename) { }
}

Now, lets say the file doesn't exist. What should you do? If you're struggling to think of the answer, that's because there isn't one... the FileInputStream doesn't know what to do about that problem. So it throws it up the chain, i.e.:

public class FileInputStream extends InputStream {
    public FileInputStream(String filename) throws FileNotFoundException { }
}

Now, lets say someone's using your library. They might have code that looks like this:

public class Main {
    public static void main(String... args) {
        String filename = "foo.txt";
        try {
            FileInputStream fs = new FileInputStream(filename);

            // The rest of the code
        } catch (FileNotFoundException e) {
            System.err.println("Unable to find input file: " + filename);
            System.err.println("Terminating...");
            System.exit(3);
        }
    }
}

Here, the programmer knows what to do, so they catch the exception and handle it.

Solution 2:

There are two cases when you should catch an exception.

1. At the lowest possible level

This is the level at which you are integrating with third party code, such as an ORM tool or any library performing IO operations (accessing resources over HTTP, reading a file, saving to the database, you name it). That is, the level at which you leave your application’s native code to interact with other components.

At this level, unexpected problems out of your control such as connection failures and locked files may occur.

You may want to handle a database connection failure by catching a TimeoutException so that you can retry after a few seconds. The same goes for an exception when accessing a file, which may be locked by a process at the moment but be available at the next instant.

The guidelines in this scenario are:

  • Handle only specific exceptions, such as SqlTimeoutException or IOException. Never handle a generic exception (of type Exception)
  • Handle it only if you have something meaningful to do about it, such as retries, triggering compensatory actions, or adding more data to the exception (e.g. context variables), and then re-throw it
  • Do not perform logging here
  • Let all other exceptions bubble up as they will be handled by the second case

2. At the highest possible level

This would be the last place where you can handle the exception before it is thrown directly to the user.

Your goal here is to log the error and forward the details to the programmers so they can identify and correct the error. Add as much information as possible, record it, and then show an apology message to the user, as there’s probably nothing they can do about it, especially if it is a bug in the software.

The guidelines in this second scenario are:

  • Handle the generic Exception class
  • Add more information from current execution context
  • Log the error and notify the programmers
  • Show an apology to the user
  • Work it out as soon as you can

The reasoning behind these guidelines

First, is that exceptions represent irreversible errors. They represent represent a bug in the system, a mistake made by the programmers, or a situation beyond the control of the application.

In these cases, there is usually little or nothing the user can do. Thus, the only thing you can do is log the error, take the necessary compensatory actions, and apologize to the user. If it is a mistake that the programmers made, it is best to let them know and fix it, working towards a more stable version.

Second, try catch blocks can mask application execution flow depending on how they are used. A try catch block has a similar function to that of a label and its goto companion, which causes the application execution flow to jump from one point to another.


When to throw exceptions

Easier to explain in the context of developing a library. You should throw when you reached an error and there's nothing more you can do besides letting the consumer of your APIs know about it, and letting them decide.

Imagine you're the developer of some data access library. When you reach a network error, there's nothing you can do besides throwing an exception. That's an irreversible error from a data access library standpoint.

This is different when you're developing a website. You would likely catch such exception in order to retry, but would want to throw an exception in case you received invalid parameters from outer layers since they should have been validated there.

Which is again different in a Presentation layer, where you expect the user to provide invalid parameters. In that case you just show a friendly message instead of throwing an exception.


As featured at https://roaddd.com/the-only-two-cases-when-you-should-handle-exceptions/