Guide | Java

How to Handle Exceptions in Java

How to Handle Exceptions in Java

Exception Handling in Java

The classic definition of an exception is an event that occurs during the execution of a program and that disrupts the normal flow of instructions. Java exceptions are specialized events that indicate something bad has happened in the application, and the application either needs to recover or exit.

Why handle Java exceptions?

Java exception handling is important because it helps maintain the normal, desired flow of the program even when unexpected events occur. If Java exceptions are not handled, programs may crash or requests may fail. This can be very frustrating for customers and if it happens repeatedly, you could lose those customers.

The worst situation is if your application crashes while the user is doing any important work, especially if their data is lost. To make the user interface robust, it is important to handle Java exceptions to prevent the application from unexpectedly crashing and losing data. There can be many causes for a sudden crash of the system, such as incorrect or unexpected data input. For example, if we try to add two users with duplicate IDs to the database, we should throw an exception since the action would affect database integrity.

Developers can predict many of the Java exceptions that a piece of code is capable of throwing.

The best course of action is to explicitly handle those exceptions to recover from them gracefully. As we will see ahead, programming languages provide ways to handle exceptions starting from specific ones and moving toward the more generic ones. Java exceptions that you cannot easily predict ahead of time are called unhandled exceptions. It’s good to capture these too in order to gracefully recover. Tracking these Java exceptions centrally offers visibility to your development team on the quality of the code and what causes these errors so they can fix them faster.

Tracking Exceptions in Java

One thing that most experienced developers will agree with is that exceptions will happen in your application, no matter how well you write your program. You cannot predict the runtime environment entirely, especially that of your customer’s.

The standard practice is to record all events in the application log file. The log file acts as a time machine helping the developer (or analyst) go back in time to view all the phases the application went through and what led to the Java exception.

For small-scale applications, going through a log file is easy. However, enterprise applications can serve thousands or even millions of requests per second. This makes manual analysis too cumbersome because errors and their causes can be lost in the noise. This is where error monitoring software can help by grouping duplicates and providing summarized views of the top and most recent Java errors. They can also capture and organize contextual data in a way that’s easier and faster than looking at logs.

How to handle exceptions in Java

Let's start with the basics of exception handling in Java before we move to more advanced topics. The try-catch is the simplest method of handling exceptions. Put the code you want to run in the try block, and any Java exceptions that the code throws are caught by one or more catch blocks.

This method will catch any type of Java exceptions that get thrown. This is the simplest mechanism for handling exceptions.

try {
  // block of code that can throw exceptions
} catch (Exception ex) {
  // Exception handler

  // Push the handled error into Rollbar
  rollbar.error(ex, "Hello, Rollbar");
}

Note: You can’t use a try block alone. The try block should be immediately followed either by a catch or finally block.

Catching specific Java exceptions

You can also specify specific exceptions you would like to catch. This allows you to have dedicated code to recover from those errors. For example, some Java errors returned from a REST API are recoverable and others are not. This allows you to treat those conditions separately.

A try block can be followed by one or more catch blocks, each specifying a different type. The first catch block that handles the exception class or one of its superclasses will be executed. So, make sure to catch the most specific class first.

try {
  // block of code that can throw exceptions
} catch (ExceptionType1 ex1) {
  // exception handler for ExceptionType1

  // Push the handled error into Rollbar
  rollbar.error(ex1, "Hello, Rollbar");
} catch (ExceptionType2 ex2) {
  // Exception handler for ExceptionType2

  // Push the handled error into Rollbar
  rollbar.error(ex2, "Hello, Rollbar");
}

If an exception occurs in the try block, the exception is thrown to the first catch block. If not, the Java exception passes down to the second catch statement. This continues until the exception either is caught or falls through all catches.

The finally block

Any code that must be executed irrespective of occurrence of an exception is put in a finally block. In other words, a finally block is executed in all circumstances. For example, if you have an open connection to a database or file, use the finally block to close the connection even if the try block throws a Java exception.

try {
  // block of code that can throw exceptions
} catch (ExceptionType1 ex1) {
  // exception handler for ExceptionType1

  // Push the handled error into Rollbar
  rollbar.error(ex1, "Hello, Rollbar");
} catch (ExceptionType2 ex2) {
  // Exception handler for ExceptionType2

  // Push the handled error into Rollbar
  rollbar.error(ex2, "Hello, Rollbar");
} finally {
  // finally block always executes
}

Handling uncaught or runtime Java exceptions

Uncaught or runtime exceptions happen unexpectedly, so you may not have a try-catch block to protect your code and the compiler cannot give you warnings either. Thankfully, Java provides a powerful mechanism for handling runtime exceptions. Every Thread includes a hook that allows you to set an UncaughtExceptionHandler. Its interface declares the method uncaughtException(Thread t1, Throwable e1). It will be invoked when a given thread t1 terminates due to the given uncaught exception e1.

Thread.setDefaultUncaughtExceptionHandler(new
Thread.UncaughtExceptionHandler() {
  public void uncaughtException(Thread t1, Throwable e1) {
    // Exception handling code  

    // Push the error into Rollbar
    rollbar.error(e1, "Hello, Rollbar");
  }
});  

Track, Analyze and Manage Java Errors With Rollbar

Managing errors and Java exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing Java errors easier than ever. Learn more about Rollbar’s features for Java and then sign up for a free trial.