Exception handling in Java (with examples)

Exception handling is a must-use tool for programmers. It avoids the uncomfortable app crashes that we see often when using certain software.

So, let’s get to it.

Table of Contents

What is an Exception?

An exception in a programming language is an unexpected event that stops the current flow execution of a program.

Some examples of exceptions are:

  • The (in) famous blue screen in Microsoft Windows.
  • When you are using an app on your phone, the app just closes without any further notice.
  • In your computer, an application closes and the operating system shows you a crash report window.

In short, when an exception occurs, the user won’t be able to keep using the application at that moment (until the app is restarted). This can cause loss of information, inconsistency in the data stored, etc.

So, as a software developer (or programmer), you should make sure that your application doesn’t crash, or at least, that it “crash gracefully”.

For instance, if you are taking the Google Associate Android Developer certification exam, you must submit an app. If this app crashes, you are immediately disqualified. That’s how important it is this topic for a developer.

What is Exception Handling?

Exception handling is the way that software developers deal with exceptions. It is what every programmer must do to make sure that the application won’t crash.

We can have two types of exceptions: the type that we can plan how to recover, and the type that the application will definitely crash.

Examples of the second type are:

  • If the computer memory is full. Apps need memory to be executed. If there is not enough memory, the app will crash and there is nothing we can do about it. Except, to make sure that there is enough memory before the app is executed.
  • The operating system fails. In this case, not only your app will crash, but the whole operating system. A typical error when this situation can happen is in UNIX based systems when you get the error “Kernel Panic“.
  • Among others.

There are some types of exceptions that you can plan beforehand how to recover:

  • Wrong user input. This one happens when you ask for a number, and you get a string. If you don’t handle this type of situation, your program will eventually crash when a user enters the wrong type of input.
  • When you are doing divisions. As you should know from mathematics, division by 0 is not defined. If you try to divide by 0 in your app, it will crash. Let’s say you are creating a calculator; you must consider this situation.
  • You want to save data to a file. If you (the computer user), don’t have writing permissions in the folder/file you want to save the data to, an exception will occur. Here, if you don’t handle the exception your app will crash. A possible way of handle this type of exception is to tell the user he/she does not have enough permission to write to that file/folder, and you give the option of choosing another location/file.

By now, you should have a clear idea of what exceptions are and why they have to be handled by the software developer.

Let’s see now what tools we have available to implement exception handling in Java.

Java blocks for exception handling

In Java, as in any other programming language, we have three type blocks to handle exceptions.

  • try: within this block, you should write the instructions that can create an exception. Like a division instruction.
  • catch: withing this block you will write the code you want to be executed in the case that an exception happens. If there is a division by 0 exception, in this section you can write a code that will tell the user division by 0 is undefined and shows a prompt asking for a different number.
  • finally: the code within this block, will always be executed, whether an exception happens or not. This block is useful to do compulsory steps, like closing a file, deleting temporary files, etc.

Let’s see the Java code for the division example without exception handling.

Scanner scanner = new Scanner(System.in);
System.out.print("Enter the dividend: ");
int dividend = scanner.nextInt();
System.out.print("Enter the divisor: ");
int divisor = scanner.nextInt();
float result = dividend/divisor;
System.out.println("The result is: " + result);

If you execute this code, with inputs 10 and 5, you will get the following result.

Java program output example
Java program output example

If the user enters the value 0 as the divisor, then an exception will occur, as in the image below.

Example of output when an exception occur
Example of output when an exception occur

If you add exception handling to your code, it will look like this:

Scanner scanner = new Scanner(System.in);
System.out.print("Enter the dividend: ");
int dividend = scanner.nextInt();
System.out.print("Enter the divisor: ");
int divisor = scanner.nextInt();
try {
    float result = dividend / divisor;
    System.out.println("The result is: " + result);
}
catch (Exception ex){
    System.out.println("Division by 0 is undefined");
    System.out.println("Please enter another divisor");
}

In this case, if the user enters the value 0 as the divisor, it will get the result below.

Java program output example with exception handling
Java program output example with exception handling

In this case, the app will still close. However, the user of the app will know what went wrong.

Notice that a user of a computer, usually don’t know what an exception is. Also, he or she won’t understand the error message:

Exception in thread “main” java.lang.ArithmeticException: / by zero at com.RP.Main.main(Main.java:98)

That’s one of the reasons why it is important to handle exceptions. So, the user knows what went wrong and can correct the input to obtain the desired output.

In our previous example, we can also use a loop to keep asking the user to enter a divisor different from 0. That is a better way because the user won’t have to open again the application to keep using it.

Also, remember there are different ways to solve the same problem, this is especially true in programming. In this example, you can use a conditional statement to avoid the app crash. But you will find cases in which you won’t be able to do it like that. Such a case is when you are working with files.

Exception Classes Hierarchy

From the code example in the previous section, you can see this line of code:

catch (Exception ex){“

This means that the exception we are planning to catch will be store in a variable named ex, and the type of that variable is Exception.

“Exception” is a Java class that will give us access to details about the exception that occurred. But this one is not the only class.

Find below the exception-related class hierarchy.

Example of exception hierarchy in Java. Source: Oracle Java docs.
Example of exception hierarchy in Java. Source: Oracle Java docs.

As you can see, we have different types of exceptions. The indentation in the classes above shows that one class inherits from another one. For instance, RuntimeException inherits from Exception, ArithmeticException inherits from RuntimeException and so on.

How can we use this?

There are cases in which more than an exception can occur. 

Because we have to give precise information to the users on what happens while using the software, it is always recommended that the error message you show to the user is as specific as possible.

In our previous example of the division, two exceptions can occur ArithmeticException (division by 0) and InputMistmatchException (if you enter a string instead of a number).

What to do in this case?

Programming languages give you the possibility of having as many catch blocks as you need. In this case, we can use one catch block for each of the two exceptions we identified, and an extra one in case another exception happens. See the code below.

try {
    Scanner scanner = new Scanner(System.in);
    System.out.print("Enter the dividend: ");
    int dividend = scanner.nextInt();
    System.out.print("Enter the divisor: ");
    int divisor = scanner.nextInt();
    float result = dividend / divisor;
    System.out.println("The result is: " + result);
}
catch (InputMismatchException ex){
    System.out.println("Please enter a number");  
}
catch (ArithmeticException ex){
    System.out.println("Division by 0 is undefined");
    System.out.println("Please enter another divisor");
}
catch(Exception ex){
    System.out.println("An unexpected error occurred.");
}

Notice that the class at top of the hierarchy (Exception) goes last.

When capturing several exception types, the hierarchy matters. If we use the class Exception in the first catch block, the other exceptions will never be caught. Because all the other exception-related classes inherit from the class Exception.

In other words, we always must catch first the most specific exception, and move down to the more general ones.

Also, remember that the code that can throw an exception, must be within the try block. That’s why in this case, we add to the try block the lines that expect the user to enter an integer value.

How and when to throw an exception

As programmers, sometimes we will have to create libraries for a specific purpose.

As part of these libraries, we can create our own exception types.

Let’s say we are creating a library that will implement classes that will facilitate the work with collections.

For the sake of example, let’s assume that our collections will have a maximum of 1000 elements. For instance, a list of students, cities, etc.

Because Exceptions is a topic that all programmers use, we can also use it as part of our implementation. Let’s say that when a user of our class list is trying to add an element, and there are 1000 elements already (the maximum allowed), an exception will be thrown.

For us to implement that, the first step is to create our own type of exception, because this one does not match with the ones defined in the programming language.

The way we can do it is by creating a new class that will inherit from the class Exception. We just have to give a name to the class that will indicate the type of exception.

class MaximumElementException extends Exception{

}

Yes, an empty class is enough because of inheritance. You can read about inheritance in this article.

Now, let’s implement the method addElement method.

public void addElement(Student st) throws MaximumElementException {
    if (amount >= 1000){
        throw new MaximumElementException();
    }
    else{
        // code to add the element here
    }
}

In the implementation above, you can see “ throws MaximumElementException ” as part of the method signature. Thindicatesate that this method can throw an exception of type MaximumElementException. Now when another developer will use this method, he/she will know that it is possible that an exception can occur, and he/she must handle it.

The other part of working with self-defined exceptions is when to throw it.

From the code above, we can see that if the maximum number of elements is reached, then we throw the exception.

Notice, that this maximum (1000) is defined by us, because we are implementing the class and, in our environment, the maximum number of elements in a collection is 1000. However, for someone else, it can be different. So, you must follow the considerations related to the problem you are solving.

Example: Movie shop

Given the classes Movie and MovieShop:

  1. Implement the method Save in the class MovieShop. This method saves to the specified file the information of all the movies in the array movies.
  2. Implement a method in the class MovieShop that save to a file the data of the cheapest movie.
  3. Implement a console app that read from the previously saved file and print the data on the screen.

Note: Use exception handling in all cases to create a robust code.

class Movie{
     String name;
     int price;
     public Movie(String n, int p){
        name = n; 
        price = p; 
     } 
}
class MovieShop{
     Movie []  movies;
     Public MovieShop(){
           movies  = new Movie[100];
     }
     Public void Save(String file_name){
          // Implement this method.
     } 
}

Solution

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;

class Movie {
    private String name;
    private int price;

    Movie(String name, int price){
        this.name = name;
        this.price = price;
    }
    public String toString(){
        return name + " " + String.valueOf(price);
    }

    public String getName(){
        return name;
    }
    public int getPrice(){
        return price;
    }
}
class MovieShop {
    Movie [] movies;
    int amount;

    public MovieShop(){
        movies = new Movie[1000];
        amount = 0;
    }
    public void AddMovie(Movie m)throws Exception{
        //While adding a movie, if the array is full an exception will occur
        //
        try {
            movies[amount] = m;
            amount ++;
        }
        catch (Exception e){
            throw e;
        }
    }
    public void Save(String filename) throws Exception {
        File f;
        PrintWriter pw = null;
        try{
            f = new File(filename);
            pw = new PrintWriter(f);
            for (int i = 0; i < amount; i++) {
                pw.println(this.movies[i].toString());
            }
        }
        // To catch possible errors, in this case we have to ways,
        // the best one -the only one- is to re-throw the same exception, so the user of
        // this method (save) must handle the exception. This one is the best one
        // because you don't suppose to print in class methods different than
        //the main class in a console app for example.
        // The second option, if you decide to print to the console in this
        //class method, is to catch specific exceptions to print specific
        //messages according to the error, for instance, "you don't have permission to create the file 'example.txt'"
        catch(Exception e){
            throw e;
        }
        finally{
            pw.close();
        }

    }
    public Movie CheapestMovie(){
        Movie cheapest = movies[0];
        for (int i = 1; i < amount; i++) {
            if (movies[i].getPrice() < cheapest.getPrice()){
                cheapest = movies[i];
            }
        }
        return cheapest;
    }

    public void SaveCheapestMovie(String filename)throws Exception {
        File f;
        PrintWriter pw = null;
        try{
            f = new File(filename);
            pw = new PrintWriter(f);
            pw.print(CheapestMovie().toString());
        }
        catch(Exception e){
            throw e;
        }
        finally{
            pw.close();
        }
    }
}
class MConsoleApp {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        //Implement a console app that read form the saved file
        //Notice that for implementing that, we first need to save data to a file
        // and to do that, we need to add a method for adding new elements to the array
        // in this case of students
        MovieShop ms = new MovieShop();
        try{
            ms.AddMovie(new Movie("Star trek",100));
            ms.AddMovie(new Movie("Guardians",80));
            ms.AddMovie(new Movie("Movie 1",800));
            ms.AddMovie(new Movie("Movie 2",90));
        }
        catch (IndexOutOfBoundsException e){
            // You have to provide useful information to the user
            //Remember the user possible won't know what an exception is.
            System.out.println("The array is full");
        }
        catch(Exception e){
            // If you catch a generic exception, you wont know how to
            //give a specific message related to the error, so if you catch
            //a generic exception, you must print a generic message.
            System.out.println("An unexpected error occurred");
        }
        finally{
            System.out.println("The movies were added");
        }

        try{
            ms.Save("Movie list.txt");
        }
        catch(IOException e){
            System.out.println("An I/O exception of some sort has occurred.");
        }
        catch (SecurityException e){
            System.out.println("A security violation has occurred.");
        }
        catch (Exception e) {
            System.out.println("An unexpected error occurred");
        }


        File f;
        Scanner scanner;
        try{
            f = new File("Movie list.txt"); // We must use the same name that was used to save the file
            scanner = new Scanner(f);
            while (scanner.hasNext()){
                System.out.println(scanner.nextLine());
            }
        }
        catch(FileNotFoundException e){ // Give meaningfull information about the error.
            System.out.println("The file you trying to read does not exists.");
        }
        catch (SecurityException e){
            System.out.println("A security violation has occurred.");
        }
        catch (Exception e) {
            System.out.println("An unexpected error occurred");
        }
    }

}

Summary

To handle exceptions, we use a (or several, as many as we need) block try-catch-finally. The block finally is not compulsory, you use it if you need to do something regardless of whether an exception occurred or not.

Withing the block catch, you always must give meaningful information to the user. Remember if the user does not have programming training (most of them don’t), they won’t understand a message ArithmeticException. If the user gets the same error every time, the result will be your app will be deleted, and we don’t want that to happen.

When using several catch blocks, you need to consider the level of each type of exception in the exception hierarchy. You should start for the class that is lower in the hierarchy and finish on the class that is highest on the hierarchy ( the class Exception).

Related article:

Software crash: exception handling in python

2 thoughts on “Exception handling in Java (with examples)”

Comments are closed.