Provide Best Programming Tutorials

Java Exception

In this article, you will learn

  • What Is The Exception In Java
  • Java Exception Handler
  • Java Exception Hierarchy
  • Java Exception Type
  • try-catch-finally
  • throws/throw keyword
  • Java 7 Automatic Resource Management and Catch block improvements
  • Exception Handling In Java – Creating Custom Exception Classes
  • Exception Handling In Java – Best Practices
  • Advantages of Exceptions

 

What Is Exception?

An Exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program’s instruction.

Exception handling enables a program to deal with exceptional situations and continue its normal execution.

Runtime errors occur while a program is running if the JVM detects an operation that is impossible to carry out. For example, if you access an array using an index that is out of bounds, you will get a runtime error with an ArrayIndexOutOfBoundsException. If you enter a double value when your program expects an integer, you will get a runtime error with an InputMismatchException.

In Java, runtime errors are thrown as exceptions. An exception is an object that represents an error or a condition that prevents execution from proceeding normally. If the exception is not handled, the program will terminate abnormally. How can you handle the exception so that the program can continue to run or else terminate gracefully? Using Java exception.

Exception Handler

The runtime system searches the call stack for a method that contains a block of code that can handle the exception.This block of code is called an exception handler.

The search begins with the method in which the error occurred and proceeds through the call stack in the reverse order in which the methods were called.

When an appropriate handler is found, the runtime system passes the exception to the handler. An exception handler is considered appropriate if the type of the exception object thrown matches the type that can be handled by the handler.

Exception Hierarchy

  • All exception classes are subtypes of the java.lang.Exception class. The exception class is a subclass of the Throwable class. Other than the exception class there is another subclass called Error which is derived from the Throwable class.

  • Errors are abnormal conditions that happen in case of severe failures, these are not handled by the Java programs. Errors are generated to indicate errors generated by the runtime environment. Example: JVM is out of memory. Normally, programs cannot recover from errors.

  • The Exception class has two main subclasses: IOException class and RuntimeException Class.

Exception Type

Java’s exceptions can be categorized into two types:

  • Checked exceptions

  • Unchecked exceptions

    • Errors

    • Runtime exceptions

Checked Exception

Checked exceptions are the type that programmers should anticipate and from which programs should be able to recover. All Java exceptions are checked exceptions except those of the Error and RuntimeException classes and their subclasses.

A checked exception is an exception which the Java source code must deal with, either by catching it or declaring it to be thrown. Checked exceptions are generally caused by faults outside of the code itself – missing resources, networking errors, and problems with threads come to mind. These could include subclasses of FileNotFoundException, UnknownHostException, etc.

Example

Solution One

package exception.trycatchresourcedemo.checkedexception;

import java.io.*;

class Main {
    public static void main(String[] args) {
        FileReader file = null;
        try {
            file = new FileReader("A.txt");
            BufferedReader fileInput = new BufferedReader(file);

            // Print first 3 lines of file "C:\test\a.txt"
            for (int counter = 0; counter < 3; counter++)
                System.out.println(fileInput.readLine());
            fileInput.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Solution Two:

package exception.trycatchresourcedemo.checkedexception;

import java.io.*;

class Main {
    public static void main(String[] args) throws Exception {
        FileReader file = null;

        file = new FileReader("A.txt");
        BufferedReader fileInput = new BufferedReader(file);

        // Print first 3 lines of file "C:\test\a.txt"
        for (int counter = 0; counter < 3; counter++)
            System.out.println(fileInput.readLine());
        fileInput.close();

    }
}

Famous Checked Exception

Name Description
IOException While using file input/output stream related exception
SQLException. While executing queries on database related to SQL syntax
DataAccessException Exception related to accessing data/database
ClassNotFoundException Thrown when the JVM can’t find a class it needs, because of a command-line error, a classpath issue, or a missing .class file
InstantiationException Attempt to create an object of an abstract class or interface.

Unchecked Exception

Unchecked exceptions inherit from the Error class or the RuntimeException class. Many programmers feel that you should not handle these exceptions in your programs because they represent the type of errors from which programs cannot reasonably be expected to recover while the program is running.

When an unchecked exception is thrown, it is usually caused by a misuse of code – passing a null or otherwise incorrect argument.

Name Description
NullPointerException Thrown when attempting to access an object with a reference variable whose current value is null
ArrayIndexOutOfBound Thrown when attempting to access an array with an invalid index value (either negative or beyond the length of the array)
IllegalArgumentException. Thrown when a method receives an argument formatted differently than the method expects.
IllegalStateException Thrown when the state of the environment doesn’t match the operation being attempted,e.g., using a Scanner that’s been closed.
NumberFormatException Thrown when a method that converts a String to a number receives a String that it cannot convert.
ArithmaticException Arithmetic error, such as divide-by-zero.

Example

package exception.trycatchresourcedemo.uncheckedexception;

public class UncheckedExceptionDemo {

    public static void main(String[] args) {
        int a = 1;
        int b = 0;
        int c = a / b;
        System.out.printf("c=" + c);
    }

}

 

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at exception.trycatchresourcedemo.uncheckedexception.UncheckedExceptionDemo.main(UncheckedExceptionDemo.java:8)

Process finished with exit code 1

Catching Exceptions

A method catches an exception using a combination of the try and catch keywords.

A try/catch block is placed around the code that might generate an exception.

Code within a try/catch block is referred to as protected code, and the syntax for using try/catch looks like the following

try{
    //protected code
}catch(ExceptionName e1){
    //Catch block
}

 

Try Catch Demo

package exception.trycatchresourcedemo;

import java.io.FileReader;
import java.io.IOException;

public class TryCatchRresourceDemo {
    public static void main(String args[]) {
        try (FileReader fr = new FileReader("E://file.txt")) {
            char[] a = new char[50];
            fr.read(a);   // reads the contentto the array
            for (char c : a)
                System.out.print(c);   // prints the characters one by one
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Multiple Catch Blocks

you can have any number of them after a single try. If an exception occurs in the protected code, the exception is thrown to the first catch block in the list.

If the data type of the exception thrown matches ExceptionType1, it gets caught there. If not, the exception passes down to the second catch statement.

This continues until the exception either is caught or falls through all catches, in which case the current method stops execution and the exception is thrown down to the previous method on the call stack.

try{
       //proteced code
   }catch(ExceptionType e1){
       //catch block
   }catch(ExceptionType e2){
       //catch block
   }catch(ExceptionType e3){
       //catch block
   }

Multiple Catch Example

package exception.trycatchresourcedemo.checkedexception;

import java.io.*;

class Main {
    public static void main(String[] args)  {
        FileReader file = null;
        try {
            file = new FileReader("A.txt");
            BufferedReader fileInput = new BufferedReader(file);
            // Print first 3 lines of file "C:\test\a.txt"
            for (int counter = 0; counter < 3; counter++)
                System.out.println(fileInput.readLine());
            fileInput.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

Since Java 7, you can handle more than one exception using a single catch block, this feature simplifies the code.

package exception.trycatchresourcedemo.multipletrycatch;


public class MultipleTryCatchDemo {

    public static void main(String[] args) {
        try {
            int a = 1;
            int b = 0;
            int c = a / b;
        } catch (ArrayIndexOutOfBoundsException | OutOfMemoryError e) {
            System.out.println(e);
        }
    }
}

The Throws/Throw Keywords

  • If a method does not handle a checked exception, the method must declare it using the throws keyword. The throws keyword appears at the end of a method’s signature.
  • You can throw an exception, either a newly instantiated one or an exception that you just caught, by using the throw keyword.
  • Try to understand the difference between throws and throw keywords, throws is used to postpone the handling of a checked exception and throw is used to invoke an exception explicitly.
package exception.trycatchresourcedemo.throwsAnException;

import java.rmi.RemoteException;

public class ThrowsAnExceptionDemo {

    public void deposit(double amount) throws RemoteException {
        // Method implementation
        throw new RemoteException();
    }
    // Remainder of class definition
}

The Finally Block

  • The finally block follows a try block or a catch block. A finally block of code always executes, irrespective of occurrence of an Exception.
  • Using a finally block allows you to run any cleanup-type statements that you want to execute, no matter what happens in the protected code.
package exception.trycatchresourcedemo.finallydemo;

public class FinallyDemo {
    public static void main(String[] args) {
        try {
            System.out.println(1 / 0);
        } catch (RuntimeException ex) {
            System.out.println(ex);
        } finally {
            System.out.println("Finally block executed!");
        }
    }
}

output

java.lang.ArithmeticException: / by zero
Finally block executed!

 

The try-with-resources

Generally, when we use any resources like streams, connections, etc. we have to close them explicitly using finally block. In the following program, we are reading data from a file using FileReader and we are closing it using finally block.

try-with-resources, also referred as automatic resource management, is a new exception handling mechanism that was introduced in Java 7, which automatically closes the resources used within the try catch block.

To use this statement, you simply need to declare the required resources within the parenthesis, and the created resource will be closed automatically at the end of the block. Following is the syntax of try-with-resources statement.

package exception.trycatchresourcedemo.trywithresourcesdemo;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class TryWithResourcesDemo {
    public static void main(String[] args) {
        try (FileReader fr = new FileReader("myFile.txt")) {
            char a[] = new char[16];
            fr.read(a);
            for (char item : a) {
                System.out.print(item);
            }


        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • To use a class with try-with-resources statement it should implement AutoCloseable interface and the close() method of it gets invoked automatically at runtime.
  • You can declare more than one class in try-with-resources statement.
  • While you declare multiple classes in the try block of try-with-resources statement these classes are closed in reverse order.
  • Except the declaration of resources within the parenthesis everything is the same as normal try/catch block of a try block.
  • The resource declared in try gets instantiated just before the start of the try-block.
  • The resource declared at the try block is implicitly declared as final.

User-defined Exceptions

You can create your own exceptions in Java.

Keep the following points in mind when writing your own exception classes −

  • All exceptions must be a child of Throwable
  • If you want to write a checked exception that is automatically enforced by the Handle or Declare Rule, you need to extend the Exception class
  • If you want to write a runtime exception, you need to extend the RuntimeException class

User-defined Exception Example

package exception.userdefineexception;

public class InsufficientFundsException extends Exception {
    private double amount;

    public InsufficientFundsException(double amount) {
        this.amount = amount;
    }

    public double getAmount() {
        return amount;
    }
}
package exception.userdefineexception;

public class CheckAccount {
    private double amount;

    public CheckAccount(double amount) {
        this.amount = amount;
    }

    public double withdraw(double number) throws InsufficientFundsException {
        if (number > this.amount) {
            throw new InsufficientFundsException(number - amount);
        } else {
            return amount - number;
        }
    }
}
package exception.userdefineexception;

public class Client {
    public static void main(String[] args) {
        CheckAccount checkAccount = new CheckAccount(100);
        try {
            checkAccount.withdraw(200);
        } catch (InsufficientFundsException e) {
            System.out.println("Sorry, you lack " + e.getAmount());
            e.printStackTrace();
        }
    }
}

output

Sorry, you lack 100.0
exception.userdefineexception.InsufficientFundsException
  at exception.userdefineexception.CheckAccount.withdraw(CheckAccount.java:12)
  at exception.userdefineexception.Client.main(Client.java:7)

Advantages of Exceptions

Now that you know what exceptions are and how to use them, it’s time to learn the advantages of using exceptions in your programs.

Advantage 1: Separating Error-Handling Code from “Regular” Code

Exceptions provide the means to separate the details of what to do when something out of the ordinary happens from the main logic of a program. In traditional programming, error detection, reporting, and handling often lead to confusing spaghetti code. For example, consider the pseudocode method here that reads an entire file into memory.

readFile {
    open the file;
    determine its size;
    allocate that much memory;
    read the file into memory;
    close the file;
}

At first glance, this function seems simple enough, but it ignores all the following potential errors.

  • What happens if the file can’t be opened?
  • What happens if the length of the file can’t be determined?
  • What happens if enough memory can’t be allocated?
  • What happens if the read fails?
  • What happens if the file can’t be closed?

To handle such cases, the readFile function must have more code to do error detection, reporting, and handling. Here is an example of what the function might look like.

errorCodeType readFile {
    initialize errorCode = 0;
    
    open the file;
    if (theFileIsOpen) {
        determine the length of the file;
        if (gotTheFileLength) {
            allocate that much memory;
            if (gotEnoughMemory) {
                read the file into memory;
                if (readFailed) {
                    errorCode = -1;
                }
            } else {
                errorCode = -2;
            }
        } else {
            errorCode = -3;
        }
        close the file;
        if (theFileDidntClose && errorCode == 0) {
            errorCode = -4;
        } else {
            errorCode = errorCode and -4;
        }
    } else {
        errorCode = -5;
    }
    return errorCode;

 

There’s so much error detection, reporting, and returning here that the original seven lines of code are lost in the clutter. Worse yet, the logical flow of the code has also been lost, thus making it difficult to tell whether the code is doing the right thing: Is the file really being closed if the function fails to allocate enough memory? It’s even more difficult to ensure that the code continues to do the right thing when you modify the method three months after writing it. Many programmers solve this problem by simply ignoring it — errors are reported when their programs crash.

Exceptions enable you to write the main flow of your code and to deal with the exceptional cases elsewhere. If the readFile function used exceptions instead of traditional error-management techniques, it would look more like the following.

readFile {
    try {
        open the file;
        determine its size;
        allocate that much memory;
        read the file into memory;
        close the file;
    } catch (fileOpenFailed) {
       doSomething;
    } catch (sizeDeterminationFailed) {
        doSomething;
    } catch (memoryAllocationFailed) {
        doSomething;
    } catch (readFailed) {
        doSomething;
    } catch (fileCloseFailed) {
        doSomething;
    }
}

 

Note that exceptions don’t spare you the effort of doing the work of detecting, reporting, and handling errors, but they do help you organize the work more effectively.

Advantage 2: Propagating Errors Up the Call Stack

A second advantage of exceptions is the ability to propagate error reporting up the call stack of methods. Suppose that the readFile method is the fourth method in a series of nested method calls made by the main program: method1 calls method2, which calls method3, which finally calls readFile.

method1 {
    call method2;
}

method2 {
    call method3;
}

method3 {
    call readFile;
}

 

Suppose also that method1 is the only method interested in the errors that might occur within readFile. Traditional error-notification techniques force method2andmethod3 to propagate the error codes returned by readFile up the call stack until the error codes finally reach method1—the only method that is interested in them.

method1 {
    errorCodeType error;
    error = call method2;
    if (error)
        doErrorProcessing;
    else
        proceed;
}

errorCodeType method2 {
    errorCodeType error;
    error = call method3;
    if (error)
        return error;
    else
        proceed;
}

errorCodeType method3 {
    errorCodeType error;
    error = call readFile;
    if (error)
        return error;
    else
        proceed;
}

 

Recall that the Java runtime environment searches backward through the call stack to find any methods that are interested in handling a particular exception. A method can duck any exceptions thrown within it, thereby allowing a method farther up the call stack to catch it. Hence, only the methods that care about errors have to worry about detecting errors.

method1 {
    try {
        call method2;
    } catch (exception e) {
        doErrorProcessing;
    }
}

method2 throws exception {
    call method3;
}

method3 throws exception {
    call readFile;
}

However, as the pseudocode shows, ducking an exception requires some effort on the part of the middleman methods. Any checked exceptions that can be thrown within a method must be specified in its throws clause.

Advantage 3: Grouping and Differentiating Error Types

Because all exceptions thrown within a program are objects, the grouping or categorizing of exceptions is a natural outcome of the class hierarchy. An example of a group of related exception classes in the Java platform are those defined in java.io — IOException and its descendants. IOException is the most general and represents any type of error that can occur when performing I/O. Its descendants represent more specific errors. For example, FileNotFoundException means that a file could not be located on disk.

A method can write specific handlers that can handle a very specific exception. The FileNotFoundException class has no descendants, so the following handler can handle only one type of exception.

catch (FileNotFoundException e) {
    ...
}

A method can catch an exception based on its group or general type by specifying any of the exception’s superclasses in the catch statement. For example, to catch all I/O exceptions, regardless of their specific type, an exception handler specifies an IOException argument.

catch (IOException e) {
    ...
}

This handler will be able to catch all I/O exceptions, including FileNotFoundException,EOFException, and so on. You can find details about what occurred by querying the argument passed to the exception handler. For example, use the following to print the stack trace.

catch (IOException e) {
    // Output goes to System.err.
    e.printStackTrace();
    // Send trace to stdout.
    e.printStackTrace(System.out);
}

You could even set up an exception handler that handles any Exception with the handler here.

// A (too) general exception handler
catch (Exception e) {
    ...
}

The Exception class is close to the top of the Throwable class hierarchy. Therefore, this handler will catch many other exceptions in addition to those that the handler is intended to catch. You may want to handle exceptions this way if all you want your program to do, for example, is print out an error message for the user and then exit.

In most situations, however, you want exception handlers to be as specific as possible. The reason is that the first thing a handler must do is determine what type of exception occurred before it can decide on the best recovery strategy. In effect, by not catching specific errors, the handler must accommodate any possibility. Exception handlers that are too general can make code more error-prone by catching and handling exceptions that weren’t anticipated by the programmer and for which the handler was not intended.

As noted, you can create groups of exceptions and handle exceptions in a general fashion, or you can use the specific exception type to differentiate exceptions and handle exceptions in an exact fashion.

Leave a Reply

Close Menu