2

So I'm working on a little project in Java and I've come down to the main method and I'm unsure how I should handle try-catching exceptions correctly.

Should I be:

Try-catching specific lines of code that I know will probably throw an exception? Like:

public class Stuff {
    public static void main(String[] args) {
        try {
            // code that will probably throw exception 1 or 2
        } catch (exception1 e) {
            // handle exception 1
        } catch (exception2 e) {
            // handle exception 2
        }

        //rest of code that probably won't throw any exceptions
    }
}

OR

Try-catching the whole main method even if some of the code in the try block will not throw an exception? Like:

public class Stuff {
    public static void main(String[] args) {
        try {
            // code that will probably throw exception 1 or 2
            // rest of code that probably won't throw any exceptions
        } catch (exception1 e) {
            // handle exception 1
        } catch (exception2 e) {
            // handle exception 2
        }
    }
}
user3053240
  • 33
  • 1
  • 6
  • 1
    Possible duplicate of [Is it expensive to use try-catch blocks even if an exception is never thrown?](http://stackoverflow.com/questions/16451777/is-it-expensive-to-use-try-catch-blocks-even-if-an-exception-is-never-thrown) – MaxG Feb 14 '16 at 22:19
  • 1
    Whichever you find more readable is going to be better for you. – Robert Dean Feb 14 '16 at 22:22
  • @rdean400, That makes sense. I was wondering if there was any sort of convention or something where one would be preferable (not from an optimization standpoints) but I suppose there really isn't a difference after reading Maxim Golman's link. Thanks! – user3053240 Feb 14 '16 at 22:26
  • Ideally, we should have smaller try blocks, and have specific exception handling logic very close to the source of exceptions. But, that might be too verbose, and we tend to be lazy; so if we can get away with coarser blocks we would. – ZhongYu Feb 15 '16 at 00:27

2 Answers2

3

One thing to consider is whether or not the code running after the catch block would still be valid if an exception was thrown. For example, consider the following method:

private void readFile()
{
    List<String> lines = null;
    try
    {
        lines = Files.readAllLines(Paths.get("/to/my/file.txt"));
    }
    catch (IOException e)
    {
        // log exception...
    }

    for (String line : lines)
    {
        System.out.println(line);
    }
}

If readAllLines throws that IOException, then the code after the catch block will throw a NullPointerException.


There's a bigger question of deciding when to catch vs re-throw an exception. I answer it by asking myself this question:

"Can my method fulfill its contract if this exception is thrown?"

YES: Handle the exception and continue to fulfill the method's contract.
NO: Re-throw the exception (either in throws clause or wrap in a more appropriate exception type).

For example, with this method,

public static List<String> readAllLines(Path path) throws IOException

if the file does not exist, it cannot return a list of the lines of the file, so it throws an IOException.

On the other hand, this method

public static boolean deleteIfExists(Path path) throws IOException

does not throw an exception if the file does not exist (it instead returns the boolean to tell you what happened). One way to think of the contract of this method is, "after this method executes, there will not be a file at path". So in this case, if the file does not exist, the contract is still fulfilled.

kuporific
  • 10,053
  • 3
  • 42
  • 46
  • That makes a lot of sense and asking if the code running after the catch is dependent on the code in the try block helped me put it in perspective. In my case, the code is dependent on the try block's code, so I suppose engulfing the whole main method in a try block would be the most beneficial since it would just stop running after an exception is caught. Thanks! – user3053240 Feb 14 '16 at 22:30
2

That depends - should the non-exceptional code be executed if either exception is raised? This isn't a "best practices" question, this is a "what are your specifications?" question.

Suppose your code looks like this:

String someValue;
try {
    someValue = parseSomething();
} catch (ParseFailureException e) {
    someValue = defaultValue;
}
// Continue, possibly using the default value

In a case like this, you should wrap only the single line. On the other hand, maybe your code looks like this:

String someValue;
try {
    someValue = parseSomething();
} catch (ParseFailureException e) {
    log.fatal("The universe is crashing! Run for your lives!");
    System.exit();
}
// Continue, assuming that parsing succeeded

In that case, it's a stylistic choice. Either approach is valid, though with such an extreme failure as in this example it might be better to simply declare that the method throws something and forget the try/catch entirely. In fact, whatever your handling code is, if the only thing left for your method to do after it is to bail out, you should consider omitting the try/catch and using a throws clause instead.

This third case, however, is objectively wrong:

String someValue;
try {
    someValue = parseSomething();
} catch (ParseFailureException e) {
    log.info("something strange happened");
    // Don't bother the calling code with the exception, it can't handle it.
}
// Continue, assuming that parsing succeeded

In a case like that, the continuation code must go inside the try block.

Douglas
  • 5,017
  • 1
  • 14
  • 28
  • @kuporific mentioned the same thing as you did in regards to whether the code after the catch is dependent on the code in the try block. Thanks for the suggestion as well! It really helped putting the solution in perspective. Also, just a little off-topic question (not really actually) would it be better to throw an exception in a try-block and catching it, or just System.exit(0)? Assuming in both cases you just want to output a message and exit the program. – user3053240 Feb 14 '16 at 22:42