Java Exception

Exception mechanism helps developers find issues of their programs. Its base class is java.lang.Throwable which consists of java.lang.Error and java.lang.Exception. In this post, I will talk about five keywords about Java exception, how to catch multiple exceptions and demonstrate how to define our own exception class.


Types of Throwable Derived Class

  • Exception: Issues when compiling the Java code
    • RuntimeException: Issues when running the Java code
  • Error: Source code must be modified to fix the error

Two Approaches to Handle Exception

public static void main(String[] args) throws ParseException {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    Date date = sdf.parse("1999-0909");
    System.out.println(date);
}
public static void main(String[] args) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    Date date = null;
    try {
        date = sdf.parse("1999-0909");
    } catch (ParseException e) {
        e.printStackTrace();
    }
    System.out.println(date);
}

KeyWord 1: throw

We can use ’throw’ keyword to throw a specific exception from a specific method.

  • ’throw’ must be put inside of the method
  • ’throw’ must be followed by ’new’ keyword and an exception object or its derived object
  • For exceptions:
    • If it is a RuntimeException or its derived object, JVM will handle it (print and pause).
    • If it is a compiling exception, we need to handle it (throws or try catch).
public static int getElement(int[] arr, int index) {
    // if arr is null, throw exception
    if (arr == null) throw new NullPointerException("arr[] is null");
    // if index is invalid
    if (index < 0 || index >= arr.length) throw new ArrayIndexOutOfBoundsException("Index is invalid");
    int ele = arr[index];
    return ele;
}

KeyWord 2: throws

We can use ’throws’ keyword to ask the invoking method to handle the exception.

  • ’throws’ keyword must be put at the line of the function declaration
  • ’throws’ must be followed by exceptions (can only put the derived exception)
// We can only specify 'Exception'
// Because FileNotFoundException extends IOException extends Exception
public static void readFile(String fileName) throws FileNotFoundException, IOException {
    if (!fileName.endsWith(".txt")) {
        throw new IOException("File format is wrong!");
    }
    if (!fileName.equals("c:\\a.txt")) {
        throw new FileNotFoundException("File path is wrong!");
    }
}

// Let JVM to handle the exception
public static void main(String[] args) throws FileNotFoundException, IOException {
    readFile("c:\\a.txt");
    System.out.println("Read File");
}

KeyWord 3, 4: try … catch

We can use try … catch to handle exceptions without pausing the following program.

  • ’try’ may throw multiple exceptions, therefore, we can use multiple ‘catch’ to handle these exceptions.
public static void readFile(String fileName) throws IOException{
    if (!fileName.endsWith(".txt")) {
        throw new IOException("File format is wrong!");
    }
    System.out.println("File format is correct!");
}

// Let JVM to handle the exception
public static void main(String[] args) {
    try {
        readFile("c:\\a.pdf");
    } catch (IOException e) {
        // Throwable has 3 methods to handle exceptions
        System.out.println(e.getMessage()); // File format is wrong!
        System.out.println(e.toString()); // java.io.IOException: File format is wrong!
        e.printStackTrace();
        // java.io.IOException: File format is wrong!
        // at Demo01TryCatch.readFile(Demo01TryCatch.java:7)
        // at Demo01TryCatch.main(Demo01TryCatch.java:15)
    }
    System.out.println("Following code");
}

KeyWord 5: finally

We can use ‘finally’ keyword to force the execution of some code blocks no matter if there are exceptions or not.

If readFile() function throws an exception, then the following printing function will not be executed.

public static void main(String[] args) {
    try {
        readFile("c:\\a.txt");
        System.out.println("If the program is wrong, this sentence will not be printed!");
    } catch (IOException e) {
        System.out.println(e.getMessage()); 
    }
    System.out.println("Following code");
}

To force the printing function to execute, we can use ‘finally’ keyword.

‘finally’ keyword is normally used to recycle resources.

public static void main(String[] args) {
    try {
        readFile("c:\\a.txt");
    } catch (IOException e) {
        System.out.println(e.getMessage());
    } finally {
        System.out.println("This sentence will be printed anyway!");
    }
    System.out.println("Following code");
}

Handle Multiple Exceptions

Approach 1: Try and catch exceptions separately

public static void main(String[] args) {
    int[] arr = {1, 2, 3};
    List<Integer> list = List.of(1, 2, 3);

    try {
        System.out.println(arr[3]); // java.lang.ArrayIndexOutOfBoundsException
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println(e);
    }
    try {
        System.out.println(list.get(3)); // java.lang.ArrayIndexOutOfBoundsException
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println(e);
    }
    System.out.println("Following Code");
    
    // java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
    // java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
    // Following Code
}

Approach 2: Try once and catch exceptions one by one

public static void main(String[] args) {
    int[] arr = {1, 2, 3};

    try {
        System.out.println(arr[3]); // java.lang.ArrayIndexOutOfBoundsException
        System.out.println(15 / 0); // java.lang.ArithmeticException
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println(e);
    } catch (ArithmeticException e) {
        System.out.println(e);
    }
    System.out.println("Following Code");

    // java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
    // Following Code
}
  • Derived exception must be caught first.
    • Because of polymorphism, derived exception object can be accepted by the base exception class. Therefore, derived exception class defined in the next catch branch will not be invoked.

Exceptions in inheritance

  • When derived class overrides the method of the base class:
    • The overridden method can throw the same exceptions.
    • The overridden method can throw derived exceptions.
    • The overridden method can throw no exceptions.
    • The overridden method can not throw exceptions, if the base class method does not throw any exceptions.
      • The overridden method can use try catch to handle exceptions generated.
public class BaseClass {
    public void show01() throws NullPointerException, ClassCastException{}
    public void show02() throws IndexOutOfBoundsException{}
    public void show03() throws IndexOutOfBoundsException{}
    public void show04() {}
}

class DerivedClass extends BaseClass {
    @Override
    public void show01() throws NullPointerException, ClassCastException {
        super.show01();
    }
    @Override
    public void show02() throws ArrayIndexOutOfBoundsException {
        super.show02();
    }
    @Override
    public void show03() {
        super.show03();
    }
    @Override
    public void show04() {
        super.show04();
    }
}

User-defined Exceptions

Define the exception class

public class RegisterException extends Exception {
    public RegisterException() {
    }

    public RegisterException(String message) {
        super(message);
    }
}

Demo

public class DemoRegisterException {

    static String[] userNames = {"Jason", "Kevin", "Joey"};

    public static void main(String[] args) throws RegisterException {
        Scanner sc = new Scanner(System.in);
        System.out.println("Please enter the user name that you want to register: ");
        String userName = sc.next();
        check(userName);
    }

    public static void check(String userName) throws RegisterException {
        for (String name : userNames) {
            if (name.equals(userName)) {
                throw new RegisterException("This user name has been occupied!");
            }
        }
        System.out.println("Success in registering this user name!");
    }
}