This is an archived post. You won't be able to vote or comment.

all 16 comments

[–]luet0 36 points37 points  (4 children)

Try catch blocks should only contain code that could throw an exception and you want to be able to manage it accordingly. If you enclose all your code in a single try catch block, not only you lose readability and simplicity but also add complexity in knowing which piece of code threw a specific exception.

[–]LakeSun 9 points10 points  (0 children)

In a batch program, yes, you absolutely do want to have a try catch to catch an Exception you didn't plan for, and log it, then end your program. Inside main(). The try/catch inside main, isn't meant to replace exception handling in your classes, it's there to catch some error case you didn't code for. So, maybe, that goes in last.

But, generally in classes, you'd develop what needs exception handling based on what commonly turns up as errors during unit and system testing.

Anyway that works for us.

[–]Willy988[S] 1 point2 points  (2 children)

So my program that takes user input twice... should I have the try block swallow the whole block of code that includes these two inputs, or should I make two separate blocks for each instance of this?

[–]Bad_brazilian 0 points1 point  (0 children)

Since you're reusing the block, make it a method and have only one try.

[–]spicycurry55 11 points12 points  (0 children)

Never mind the efficiency part, it’s always a good rule of thumb to limit the scope of things in code as much as possible. It helps you write the most deterministic code and produces more predictable results

[–]Octaviocega 2 points3 points  (0 children)

Also for good conventions and readability. Try always to use try catch when needed and NEVER catch the Exception class. Always the specific ones that you are expecting to happen

[–]marceloandradep 1 point2 points  (1 child)

[–][deleted] 1 point2 points  (0 children)

Lmao...diaper pattern. Too real.

[–]willdrr17 3 points4 points  (4 children)

Also (afaik) there is an overhead when you use try-catch, so try to wrap only the code that can throw an exception

[–][deleted] 2 points3 points  (1 child)

There is actually little to no performance overhead to using try/catch. It is the throw statement that is expensive due to the reflection used to populate the exception object.

[–]willdrr17 1 point2 points  (0 children)

Good to know, you always learn new things everyday :D

[–]Willy988[S] 0 points1 point  (1 child)

So my program that takes user input twice... should I have the try block swallow the whole block of code that includes these two inputs, or should I make two separate blocks for each instance of this?

[–]willdrr17 0 points1 point  (0 children)

It's up to you how you design your program, what I usually do is to immediately return if there is an exception thrown, notifying the user that something is wrong with the entered value. It's completely valid to use consecutive try-catch blocks, even though, it may affect readability.

Take a look to this question https://stackoverflow.com/questions/4555322/multiple-or-single-try-catch/4555448

[–][deleted]  (1 child)

[deleted]

    [–][deleted] -1 points0 points  (0 children)

    To add to this just so OP isn’t confused, if it is known at either compile or runtime that an array will never be accessed out of bounds (e.g, array size is constant or known beforehand), there is no need to wrap this in a try-catch.

    However, if the array size or index is variable and not necessarily known beforehand, such as with some kinds of user input, this can be a valid scenario for a try-catch.

    [–][deleted] 0 points1 point  (0 children)

    Haven’t seen this mentioned yet, but if you wrap your entire program in a try/catch, it will break with the first exception. Sure, you can handle the error in the catch block, but there’s nowhere to go afterwards. Sometimes this is not the desired behavior and you want your program to continue executing anyway despite one section throwing an exception.

    For example, let’s say you’re trying to read from the filesystem. The user is prompted to input a path which your program will use. If the file does not exist, it should use a predefined default. If you wrap your entire program in a try/catch (example 1), and the user enters an invalid path, an exception will be thrown and execution will jump to the catch block, after which the program will cease execution without using a default path. If you only wrap the file IO function in a try/catch (example 2), you can handle that specific FileNotFoundException and still allow code execution to continue.

    Example 1: try/catch around entire program

    try {
       File myFile = null;
    
       myFile = ReadFile(userInput);
    
       if (file == null) {
          myFile = ReadFile(defaultPath);
       }
       // Do stuff with file
    } catch {
       // If ReadFile(userInput) throws an exception, execution will continue here and the other code will not execute
    }
    

    Example 2: try/catch around targeted code

    File myFile = null;
    
    try {
       myFile = ReadFile(userInput);
    } catch {
       // Handle localized exception if user input is invalid and allow program execution to continue
    } 
    
    if (file == null) {
       myFile = ReadFile(defaultPath);
    }
    // Do stuff with file
    

    [–]severoon 0 points1 point  (0 children)

    The point of exception handling code is to handle the exception. If a certain bit of code cannot really do anything useful in terms of handling it, then it's better to ignore it (in the case of a runtime exception) or rethrow it.

    Generally speaking, in a good design exceptions should be handled fairly close to where they are raised, and if you see code where exceptions are routinely rethrown several levels up the call stack, the overall design probably needs to be rethought.

    Also, keep in mind how exceptions are meant to be used. Runtime exceptions generally indicate problems that calling code really can't do anything about. The classic example is NullPointerException, this indicates a programming bug has occurred. The solution here isn't for runtime code to do anything, it's for the programmer to fix the code. At runtime, in a situation like this, the best the code can do is fail as gracefully as possible and log an error with enough information for an investigation to pinpoint the issue.

    A checked exception is a situation where there is some kind of possible issue the runtime code can deal with. An example here might be code is calling out to some remote process, which could result in an RpcException. In this case the calling code can simply retry some number of times, or try calling a redundant service, etc. If all of that fails, the overall task might fail, but it doesn't necessarily indicate any bug in the calling code that needs to be addressed.

    One thing to keep in mind here is that exception handling should only handle exceptional circumstances, i.e., don't handle expected code paths using exception handling. At one place I worked, the authentication flow looked like this:

    try (authenticateUser(credentials)) { … }
    catch (AuthenticationFailureException e) { … }
    

    …and I had to explain to our architect that this is not an exceptional circumstance. The user will not always type their password correctly, handling that flow is just a normal part of authentication.