QQMouse
QQMouse

Reputation: 31

Java - How to properly handle a try catch block

I was wondering what is the proper convention for handling a try/catch block. It is pretty obvious what should be within the try block but what about the catch block?

Can I write a message to the user like the following:

       do {
            try {
                System.out.println("Pi to the number of decimal places:");
                Scanner in = new Scanner(System.in);
                userNth = in.nextInt();
            } catch (Exception e) {
                System.out.println("Error: Enter a number between 1 and 100");
            }
        } while(userNth < 1 || userNth > piDecimals);

Or is this bad practice?

Upvotes: 2

Views: 3539

Answers (3)

Nathan Hughes
Nathan Hughes

Reputation: 96444

Exception-handling is not the place to make rash assumptions; usually by the time this part of your code has been executed it's because something unanticipated has happened, this is when you want to be most careful to be accurate about detecting and recording what happened so that you can tell what needs fixing.

The choice of Exception as the type of exception that gets caught is too broad. The method you're calling throws 3 different exceptions for distinctly different reasons; only one of which is something that should be caught here. Also unchecked exceptions like NullPointerException will get caught by this. If you were to add some code to this catch block that inadvertently introduced a NPE it would be hard to figure out what went wrong. Your overbroad catch can result in bugs not being found or errors not getting handled properly.

(Btw Makoto makes a good point that nextInt isn't what you should be calling here anyway.)

Not logging the exception can be acceptable in narrow cases where you're certain of what the exception means (for instance, if you caught InputMismatchException, or NumberFormatException in Makoto's example code). But in combination with catching Exception it has the capacity to hide errors and cause confusion.

You likely chose to catch Exception because handling a bunch of different checked exceptions, most of which seemed unlikely to ever happen anyway, seemed like an intolerable nuisance. Providing a consistent way of handling and logging exceptions will help, by providing a reasonable default case for exceptions you don't know what to do with. That way if you see an exception you just can't handle, you always have the option of letting it be thrown (possibly catching it and wrapping it in an unchecked exception), knowing that if thrown it will get logged and end your program.

For a very small command-line program sometimes it's entirely ok to let exceptions that you can't handle be thrown from main (by adding throws Exception to the main method). This is ok for toy examples, small school projects, etc.; I'd only use it in production code if there was a plan for logging the output (like a batch file that redirects stderr to a file):

public static void main(String... args) throws Exception {
    ... application code
}

In most cases all the main method code should be placed in a try block where any Throwable is caught and logged:

public static void main(String... args) {
    try {
        ... application code here
    }
    catch (Throwable t) {
        logger.log(t);
    }
}

Either alternative makes it less tempting for you to inappropriately swallow inconvenient checked exceptions.

Upvotes: 2

Makoto
Makoto

Reputation: 106498

In all actuality, this code is not going to function the way you intend it to. There are two key reasons for this:

  • nextInt() blocks until it receives an integer; that is, it's not going to care about what input you give it until it reads an integer, and
  • Even if this were to be okay, depending on how you initialize userNth and piDecimals, one or both of those variables may not be defined, thus preventing compilation.

Also, don't catch Exception. Be as specific as you can when catching exceptions, since Exception also includes some nifty and dangerous RuntimeExceptions like NullPointerException.

What you're looking to do:

  • Take in an integer input
  • If the user enters a non-integer, tell them they need to enter an integer
  • Keep doing this while userNth < 1 || userNth > piDecimals.

To that, we should look to get the right exception thrown by parsing the input as a string first, then as an Integer:

try {
    System.out.println("Pi to the number of decimal places:");
    userNth = Integer.parseInt(in.nextLine());
} catch (NumberFormatException e) {
    System.out.println("Error: Enter a number between 1 and 100");
    // You have to set this value to something so that userNth is defined!
    userNth = Integer.MAX_VALUE;
}

The other part to this is that you have to decide what message you show if userNth > 1 && userNth < piDecimals, since your try...catch isn't going to cover that. This, I leave as an exercise for the reader.

Upvotes: 1

Socratic Phoenix
Socratic Phoenix

Reputation: 556

Simple Answer: what you wrote is fine

Longer Answer: try-catch blocks are for executing code that may throw an exception, and then handling said exception if it occurs. In general, the catch block should have code that handles the exception however you need to handle it. If the statement you currently have is how you want to respond to an exception, then it's fine by convention. Some common things to do in a catch block are:

  • Throw another exception that encapsulates the thrown exception. (I often do this when parsing so that there can be a single ParseException)
  • Throw a runtime exception encapsulating the thrown exception and let java's default uncaught exception handler deal with it. (I do this a lot when I'm writing quick temporary programs and I don't want to deal with checked exceptions)
  • Pass it to some generic handler in your program, such as a GUI to display the error, etc.
  • call printStacktrace on it

But anything that fits your exception-handling needs is fine

Upvotes: 1

Related Questions