Java Basics: Exception Handling

All about handling exceptions in Java

This is the second post in a series on some of the basics of the Java programming language.  As with the first post, this is going to bore anybody who is already familiar with Java.

Posts in the Series

  1. Java Basics: Control Flow Statements
  2. Java Basics: Exception Handling (this post)
  3. Java Basics: Custom Exception
  4. Java Basics: Arrays and Collections
  5. Java Basics: Maps
  6. Java Basics: File I/O
  7. Java Basics: NIO Files

Prerequisites

  • Working version of Java
  • Basic understanding of programming concepts

Definitions

Exception

An exception is two things in Java: 1.) an event that happens during the execution of an application that interferes with it’s proper flow. 2.) An object created by Java when such an event occurs.  A subclass of java.lang.Exception.

Exception Handler

A block of code that can handle an exception that’s been thrown.  The handler must specify the same type of exception that has been thrown.

Call Stack

When an exception is thrown, the runtime system looks for an exception handler for that exception.  Starting with the method in which the exception is thrown, the runtime system “bubbles up” through the methods.  This series of methods is the call stack.

StackTrace

Checked Exception

Exceptions that an application is expected to anticipate and recover from.  The classic example of this is File IO.  The user enters a file name and if the file doesn’t exist an exception is thrown.  The application should catch that exception and give the user a chance to provide another file name (or gracefully recover in some other way).  Checked exceptions must be caught or specified (throws keyword on a method) or there is a compile error.

Error

Errors are exceptions that are external to the application.  Typically the application won’t be able to recover from an error.  It depends on the situation whether or not it makes the most sense to catch the error and report it to the user or just exit with a stack trace.  There’s no requirement to catch or specify an error.

Runtime Exception

Exceptions that happen within the code of an application that the application doesn’t anticipate or recover from.  These are most often the result of a programming error so it usually makes the most sense to fix the bug rather than to catch the error.  There’s no requirement to catch or specify a runtime exception.  Runtime Exceptions are subclasses of java.lang.RuntimeException.  There is also no requirement to catch or specify runtime exceptions.

Unchecked Exception

Errors and runtime exceptions are both considered unchecked exceptions.

 

try-catch

The example below demonstrates a simple try-catch statement.  Parsing a number throws the checked exception java.text.ParseException.  In a real-world application, you could catch the exception and then ask the user for better input if it throws the ParseException, so the application can be expected to both anticipate and recover from this scenario.  The try-catch statement has two parts: the try block and the catch block.  The try block should contain any code that might throw the exception specified in the catch.  The catch block first defines the type of exception being caught and assigns it to a variable (in this case type is ParseException and the variable name is e).  The Code within the curly braces is what will execute if the specified exception is caught.  In this case, it explains what went wrong and asks for appropriate input.  If a bit of code could possibly throw more than one exception, additional catch blocks can be added.

String priceOfSmallCoffee= "2.566"; // For a valid amount change to $2.56
Number amount = 0;
try {
   amount = NumberFormat.getCurrencyInstance().parse(priceOfSmallCoffee);
} catch (ParseException e) {
   System.err.println("Invalid Input '" + priceOfSmallCoffee + "'");
   System.err.println("Please provide valid currency input '$#.##");
}

Running this code, will catch the exception and provide a nice explanation to the user about why their input was invalid.

Invalid Input '2.566'
Please provide valid currency input '$#.##

throws

Sometimes handling the exception in the method in which it occurs isn’t what you want to do.  In that case, a checked exception can be “thrown” using a throws clause on the method that contains the code that can throw an exception.  In the example below, notice the throws ParseException after the method name and also that there is no try-catch in the code.  The exception here is thrown upward and then must be caught or thrown in the calling method (in this case, main to keep the example simple).  If you need to throw multiple exceptions, just separate them with a comma.

public static Number getAmount() throws ParseException {
   String priceOfSmallCoffee = "2.566"; // For a valid amount change to $2.56
   Number amount = 0;
   amount = NumberFormat.getCurrencyInstance().parse(priceOfSmallCoffee);
   return amount;
}

finally

Sometimes (file IO – I’m looking at you), you have resources open that must be closed when you’re done with them.  When an exception is thrown, it doesn’t finish executing the code in the try block, but leaves and goes right into the catch area.  If the code for closing file resources is at the end of the try block, it won’t run when there’s an error and will potentially cause other problems.  The finally block runs reliably unless something major happens like the JVM abruptly exiting or the running thread being killed.  In the code below, the FileWriter object throws the checked exception IOException.  The FileWriter needs to be closed when we’re done with it even if it throws an exception while writing.  The code in the finally block will run if it operates normally or if an IOException is caught.

int cupsOfCoffee = 4;
float pricePerCup = 2.46f;
String outputFileName = "output.txt";
FileWriter fw = null;

try {
   fw = new FileWriter(outputFileName);
   fw.write("Cups " + cupsOfCoffee + " at $" + pricePerCup + "ea. = $" + cupsOfCoffee * pricePerCup);
} catch (IOException e) {
   System.err.println("An error occurred while writing the output.");
   System.err.println(e.getMessage());
} finally {
   if (fw != null) fw.close();
}

A finally can also be used without any catch blocks.  If for some reason you’d prefer to throw the IOException, you can use the code below to make sure the FileWriter object gets closed.  It’s identical to the previous example, except for the catch block being missing.

try {
   fw = new FileWriter(outputFileName);
   fw.write("Cups " + cupsOfCoffee + " at $" + pricePerCup + "ea. = $" + cupsOfCoffee * pricePerCup);
} finally {
   if (fw != null) fw.close();
}

try-with-resources

When using objects that may tie up resources until they’re closed, as is the case with certain File IO objects, you can use a try-with-resources statement.  It can be used with any class that implements java.lang.AutoCloseable or any of its subinterfaces.  A try-with-resources can still have catch and finally blocks as needed.  In this version of the File IO example with been using, we declare the FileWriter object in the parenthesis immediately following the try keyword.  The FileWriter instance will automatically be closed, regardless of whether the try code runs normally or throws an Exception. You can declare multiple resources, just end each resource declaration with a semi-colon.  I’d also recommend putting them each on their own line for readability.

try (FileWriter fw = new FileWriter(outputFileName)) {
   fw.write("Cups " + cupsOfCoffee + " at $" + pricePerCup + "ea. = $" + cupsOfCoffee * pricePerCup);
} catch (IOException e) {
   System.err.println("An error occurred while writing the output.");
   System.err.println(e.getMessage());
}

Conclusion

This post covers the basics of handling exceptional events in a Java application.  The example code is over on github.  I’m planning a follow-up post on writing your own Exception class.

Resources

Java Documentation – Exceptions