Java 11 Developer Certification - Exception Special Concepts

May 10, 2021

We will be looking at some special and out of ordinary concepts in Exceptions in this section.

Catch Examples

For this section, we will use the below code.

package maxCode.online.exceptions;

import java.io.IOException;

class CustomThrowable extends Throwable {
	CustomThrowable(String message) {
		super(message);
	}
}

class CustomException extends Exception {
	CustomException(String message) {
		super(message);
	}
}

class SuperClass {
	public void methodSuperClass() throws CustomException {

	}
}

class SubClass extends SuperClass {
	public void methodSubClass() {
		try {
			methodSuperClass();
		} catch (Exception CustomException) {
			// ignore it
		}
	}
}

public class CatchExamples {
	public static void main(String[] args) {
		CatchExamples ce = new CatchExamples();

        try {
 
        } catch (Throwable e) {
 
        }
        //----------------------------
        try {
 
        } catch (Exception e) {
 
        }
        //----------------------------
        try {
 
        } catch (Error e) {
 
        }
        //----------------------------
        try {
 
        } catch (RuntimeException e) {
 
        }

		// Reminder, Throwable or custom subclasses of Throwable and any
		// RuntimeException descendants are checked.

		try {
			SubClass c = new SubClass();
			c.methodSuperClass();
			ce.testError();

		} catch (ArithmeticException e) {
			e = new ArithmeticException("This works");
			throw e;
		} catch (CustomException | RuntimeException | IOException e) {
			throw new RuntimeException("So many exceptions, so little time");
		}
	}

	private void testError() throws IOException {
		// We'll complete this later
	}
} 

We have a CustomThrowable class which extends Throwable, and CustomException class which extends Exception.

The testError method simply throws an IOException.

Yyou can wrap any code or no code at all in a try-catch clause as long as the catch clause does not specify checked exception. This is demonstrated by the multiple try-catch blocks which are empty in the main method. If we replace any of these runtime exception with one of our checked exceptions, we will get compiler error.

Basically, we’ve now introduced a compile error, just by wrapping a try-catch clause with a checked exception around an empty statement. It turns out that checked exceptions are two-way streets, you cannot use them in a catch clause unless you code throws that type of exception.

If we replace the multi catch line with something like below

catch (CustomException | RuntimeException | Throwable e)

the compiler will throw error. Reason being you can’t specify multiple exceptions in a single catch clause that are considered derivatives of another. They must be disjoined. If we look at the code there, they’re both CustomException and RuntimeException are derivatives of Throwable, so the compiler disallows this declaration.

Next if we try to assign some value to the catch parameter e, the compiler throws an error. It is because using a catch clause with multiple declared exceptions comes with another limitation. The parameter of the catch clause is implicitly final and you cannot assign it to another value.

But as you can see in the code, we have a single catch block for ArithmeticException where we are re-assigning e and throwing it. This works since the its a single catch block. Also the other exceptions in the multi catch block below that are placed strategically because you need to go to most specific to least specific. If we hadn’t done that, we would have received a compiler error on the RuntimeException in the multiple declaration.

The code compiles fine, but we do not get any output!

Throwing an exception in finally clause

For this section, we will use the below code

package maxCode.online.exceptions;

import java.io.IOException;

public class FinallyTry {
    public static void main(String[] args) {
        someMethodThrowsException();
    }

    public static void someMethodThrowsException() {
        try {
            System.out.println("Doing something");
        } catch (Exception e) {
            throw new IOException("Testing catch");
        } finally {
            throw new RuntimeException("Testing finally");
        }
    }
}

Output

Doing something
Exception in thread "main" java.lang.RuntimeException: Testing finally
	at maxCode.online.exceptions.FinallyTry.someMethodThrowsException(FinallyTry.java:16)
	at maxCode.online.exceptions.FinallyTry.main(FinallyTry.java:7)

We have a simple method which throws an IOException, and we are calling this method from the main method.

We are throwing the IOException back from the catch clause and there is nothing to handle it now. Still there is no compiler error!

That is because the catch clause might try to throw an I/O exception, but the finally clause always gets executed and its execution will be the exception that is actually thrown.

A runtime exception is unchecked and therefore the try catch in the calling block and the declaration in the method is no longer required.

Let’s review some of the catch clause constraints:

  • A catch clause is not required for unchecked exceptions.
  • A catch clause is required for checked exceptions, which are thrown from the code in the try block.
  • Adding a catch clause for a checked exception that is never thrown from the code in the try block is a compiler error.
  • You can have multiple catch clauses, each catch clause must specify a unique exception.
  • Multiple catch clauses should be declared from most specific to least specific.
  • It’s a compiler error to define a more specific exception, after a less specific exception in the same inheritance tree.
  • A clause that contains multiple exceptions in one clause, cannot declare two that are in the same inheritance tree in the same declaration.
  • An exception parameter is not final in a single catch exception clause.
  • But an exception parameter is implicitly final, if it is in a multiple catch exception clause.

Exceptions in static and instance initializers

So in this code we have a class StaticTest, which has two static fields currentMessage and currentVal. We have one static initializer in this class which throws an error.

package maxCode.online.exceptions;

import java.io.IOException;

class StaticTest {
	public static String currentMessage;

	// Initialized to 0
	public static int currentVal;

	// Static Initializer
	static {
		System.out.println("Initializing class StaticTest");
		try {
			// We force an error for demonstration purposes
			if ((10 / currentVal) > 0) {
				System.out.println("Whoops");
			}
		} catch (Exception e) {
			System.out.println("Caught the error");
		} finally {
			currentVal = 1;
		}
		currentMessage = "Inside Static Initializer";
	}
}

public class InitializerExceptions {
	// Create a subclass of InitializerExceptions
	class SubClass extends InitializerExceptions {

		SubClass() throws Exception {
			super(); // Note that call to super() is redundant statement
		}
	}

	// Create an instance initializer block that throws an unchecked exception
	{
		int i = 0;
		if (i == 0)
			throw new IOException("Whoops");
	}

	// Constructor declares IOException in a throws clause
	InitializerExceptions() throws IOException {

	}

	// Second constructor without a throws clause
	// InitializerExceptions(String parameterOne) {
	// try {
	//
	// } catch (IOException e) {
	// System.out.println("I'm ignoring the error");
	// }
	// }

	public static void main(String[] args) {
		System.out.println("Executing main()");
		System.out.println(StaticTest.currentMessage);

		try {
			InitializerExceptions ie = new InitializerExceptions();
		} catch (Exception e) {
			System.out.println("Ignoring the error, " + e.getMessage());
		}
	}
}

Output

Executing main()
Initializing class StaticTest
Caught the error
Inside Static Initializer
Ignoring the error, Whoops

If an exception occurs in a static initializer, the Java virtual machine cannot recover from it. The Static Initializer needs to handle the situation itself. In such case, we get a ExceptionInInitializerError.

That is why we have used the try catch finally block within the static initializer.

A finally clause is always executed, but if a new exception is not created in the finally clause, the Java Virtual Machine still looks for the calling method to handle the exception, which does not happen here.

Now this is true of any finally clause, not just one in a static initializer method. The Java Virtual Machine won’t initialise the class with the exception thrown even though we now have a finally clause.

This is exactly why we need a try-catch in the static initializer. If we just have the try-finally, it will still be throwing ExceptionInInitializerError.

The rules for checked and unchecked exceptions still hold true for Static Initializers, but for Static Initializer, you can’t declare a throws clause, so therefore you must handle a checked exception that occurs in a Static Initializer.

We also have a normal initializer in the main class which throws an IOException. Wwe could handle it with an enclosing try-catch block as we did with the Static Initializer, but for an instance initializer, we’ve also got another option. Since the instance initializer code is executed in the constructor method, we can instead add a throws declaration to the constructor. So as you can see, our constructor throws IOException.

Also remember, if your instance initializer throws an unchecked exception, every constructor in your class must declare the exception in its throw declaration. The only way to get your code to compile is to have every constructor declare the exception in its throw clause. So if we want a second constructor say with a single parameter, we can initialize it like below

InitializerExceptions(String parameterOne) throws IOException

We have also created a nested sub-class SubClass which extends InitializerException. If the super class constructor throws an exception, the subclass constructor must also explicitly throw that exception. If we dont create the constructor for our SubClass, the JVM implicitly creates a no args constructor for us which will just call super, which does have the throws declaration. If we try to contain this using try-catch, the super() call doesnt remain the first line in the constructor, again throwing error. Our only solution is to create a no args constructor that declares the same exception or a broader one than your super classes constructor.

So to summarize it all

  • An unhandled exception in a static initializer is fatal to the application, checked or not checked, if the class is ever initialised.
  • A checked exception in a static initializer is a compiler error that can only be caught and handled by the static initializer code itself.
  • An unhandled exception in an instance initializer is not fatal to the application.
  • A checked exception in an instance initializer that is not caught and handled by the instance initializer code itself is allowable if and only if all constructors declare the exception in their throws clauses.
  • A no args constructor with a throws declaration that includes a checked exception will cause trouble for any class that extends it which does not also declare a no args constructor that either throws the same exception or a broader one.

We have finally completed the last part of exception handling here, we will go through Modules in the next section.