Skip to content

Additional Exception Features

Modern versions of Java provide advanced exception-handling features to improve code clarity and reduce boilerplate.

1. Try-with-Resources

The try-with-resources statement simplifies automatic resource management (e.g., closing files or streams). When a resource is opened within the parentheses of a try, it is automatically closed when the block exits, whether normally or through an exception.

You can use this with any object that implements the AutoCloseable interface.


2. Multi-Catch

The multi-catch feature lets you catch multiple exception types in a single catch block, reducing code duplication.

java
catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
	// Handle both exceptions
}
  • Use the | operator to separate exception types.

  • The exception variable e is implicitly final—you cannot assign a new value to it.


3. Final Rethrow (More Precise Rethrow)

The final rethrow feature allows the compiler to infer the most specific type of exception that can be thrown. If a catch block rethrows the exception, Java tracks which types are possible and enforces more precise type checking. This helps avoid overly broad exception declarations.

Built-in Exceptions

Java provides a robust hierarchy of built-in exceptions. They fall into two broad categories:


Unchecked Exceptions

Unchecked exceptions are subclasses of RuntimeException. These do not need to be declared in a method’s throws clause.

ExceptionDescription
ArithmeticExceptionArithmetic error (e.g., divide-by-zero).
ArrayIndexOutOfBoundsExceptionAccessing invalid array index.
ArrayStoreExceptionStoring the wrong type in an array.
ClassCastExceptionInvalid type casting.
EnumConstantNotPresentExceptionInvalid enum constant access.
IllegalArgumentExceptionIllegal method argument.
IllegalCallerExceptionIllegal caller of a method.
IllegalMonitorStateExceptionIllegal monitor state (e.g., waiting on an unlocked thread).
IllegalStateExceptionEnvironment or application in an invalid state.
IllegalThreadStateExceptionIncompatible thread operation.
IndexOutOfBoundsExceptionIndex is out of bounds.
LayerInstantiationExceptionCannot create a module layer.
NegativeArraySizeExceptionArray size is negative.
NullPointerExceptionNull reference used improperly.
NumberFormatExceptionInvalid number format.
SecurityExceptionSecurity violation.
StringIndexOutOfBoundsExceptionString index out-of-bounds.
TypeNotPresentExceptionType not found.
UnsupportedOperationExceptionOperation is unsupported.

Checked Exceptions

Checked exceptions are not subclasses of RuntimeException, and must be declared in a method’s throws clause or handled explicitly.

ExceptionDescription
ClassNotFoundExceptionClass not found.
CloneNotSupportedExceptionAttempt to clone an object that does not implement Cloneable.
IllegalAccessExceptionAccess to a class or field denied.
InstantiationExceptionAttempt to instantiate an abstract class/interface.
InterruptedExceptionThread interrupted.
NoSuchFieldExceptionField not found.
NoSuchMethodExceptionMethod not found.
ReflectiveOperationExceptionSuperclass for reflection-related exceptions.

Creating Custom Exception Subclasses

You can define custom exceptions to handle application-specific errors. This is done by subclassing Exception (or RuntimeException if it should be unchecked).

java
// Create a custom exception
class NonIntResultException extends Exception {
	int n, d;

	NonIntResultException(int i, int j) {
		n = i;
		d = j;
	}

	public String toString() {
		return "Result of " + n + " / " + d + " is non-integer.";
	}
}

class CustomExceptDemo {
	public static void main(String[] args) {
		int[] numer = { 4, 8, 15, 32, 64, 127, 256, 512 };
		int[] denom = { 2, 0, 4, 4, 0, 8 };

		for (int i = 0; i < numer.length; i++) {
			try {
				if ((numer[i] % 2) != 0)
					throw new NonIntResultException(numer[i], denom[i]);

				System.out.println(numer[i] + " / " + denom[i] + " is " + numer[i] / denom[i]);
			} catch (ArithmeticException exc) {
				System.out.println("Can't divide by Zero!");
			} catch (ArrayIndexOutOfBoundsException exc) {
				System.out.println("No matching element found.");
			} catch (NonIntResultException exc) {
				System.out.println(exc);
			}
		}
	}
}

Output:

4 / 2 is 2
Can't divide by Zero!
Result of 15 / 4 is non-integer.
32 / 4 is 8
Can't divide by Zero!
Result of 127 / 8 is non-integer.
No matching element found.
No matching element found.

Should You Use Return Values or Exceptions?

In Java, exceptions are the preferred way to handle errors. Although returning error codes is possible, exceptions:

  • Provide a structured and consistent approach.

  • Separate normal logic from error handling.

  • Are the standard practice for professional Java developers.


Made with ❤️ for students, by a fellow learner.