try-catch-finally statements and throws clause in a method declaration


The try-finally and try-catch-finally statements

The try...catch...finally statement combines exception handling with clean-up code. The finally block contains code that will be executed in all circumstances. This makes them suitable for resource management, and other kinds of cleanup.

Try-finally

Here is an example of the simpler (try...finally) form:

try {
    doSomething(); 
} finally {
    cleanUp();
}

The behavior of the try...finally is as follows:

  • The code in the try block is executed.
  • If no exception was thrown in the try block:
    • The code in the finally block is executed.
    • If the finally block throws an exception, that exception is propagated.
    • Otherwise, control passes to the next statement after the try...finally.
  • If an exception was thrown in the try block:
    • The code in the finally block is executed.
    • If the finally block throws an exception, that exception is propagated.
    • Otherwise, the original exception continues to propagate.

The code within finally block will always be executed. (The only exceptions are if System.exit(int) is called, or if the JVM panics.) Thus a finally block is the correct place code that always needs to be executed; e.g. closing files and other resources or releasing locks.

try-catch-finally

Our second example shows how catch and finally can be used together. It also illustrates that cleaning up resources is not straightforward.

// This code snippet writes the first line of a file to a string
String result = null;
Reader reader = null;
try {
	reader = new BufferedReader(new FileReader(fileName));
	result = reader.readLine();
} catch (IOException ex) {
	Logger.getLogger.warn("Unexpected IO error", ex); // logging the exception
} finally {
	if (reader != null) {
		try {
			reader.close();
		} catch (IOException ex) {
			// ignore / discard this exception
		}
	}
}

The complete set of (hypothetical) behaviors of try...catch...finally in this example are too complicated to describe here. The simple version is that the code in the finally block will always be executed.

Looking at this from the perspective of resource management:

  • We declare the "resource" (i.e. reader variable) before the try block so that it will be in scope for the finally block.
  • By putting the new FileReader(...), the catch is able to handle any IOError exception from thrown when opening the file.
  • We need a reader.close() in the finally block because there are some exception paths that we cannot intercept either in the try block or in catch block.
  • However, since an exception might have been thrown before reader was initialized, we also need an explicit null test.
  • Finally, the reader.close() call might (hypothetically) throw an exception. We don't care about that, but if we don't catch the exception at source, we would need to deal with it further up the call stack.
Version ≥ Java SE 7

Java 7 and later provide an alternative try-with-resources syntax which significantly simplifies resource clean-up.


The 'throws' clause in a method declaration

Java's checked exception mechanism requires the programmer to declare that certain methods could throw specifed checked exceptions. This is done using the throws clause. For example:

public class OddNumberException extends Exception { // a checked exception
}
 
public void checkEven(int number) throws OddNumberException {
	if (number % 2 != 0) {
		throw new OddNumberException();
	}
}

The throws OddNumberException declares that a call to checkEven could throw an exception that is of type OddNumberException.

A throws clause can declare a list of types, and can include unchecked exceptions as well as checked exceptions.

public void checkEven(Double number)
throws OddNumberException, ArithmeticException {
	if (!Double.isFinite(number)) {
		throw new ArithmeticException("INF or NaN");
	} else if (number % 2 != 0) {
		throw new OddNumberException();
	}
}

What is the point of declaring unchecked exceptions as thrown?

The throws clause in a method declaration serves two purposes:

  • It tells the compiler which exceptions are thrown so that the compiler can report uncaught (checked) exceptions as errors.
  • It tells a programmer who is writing code that calls the method what exceptions to expect. For this purpose, it often makes to senses to include unchecked exceptions in a throws list.

Note : that the throws list is also used by the javadoc tool when generating API documentation, and by a typical IDE's "hover text" method tips.

Throws and method overriding

The throws clause forms part of a method's signature for the purpose of method overriding. An override method can be declared with the same set of checked exceptions as thrown by the overridden method, or with a subset. However the override method cannot add extra checked exceptions. For example:

public void checkEven(int number) throws NullPointerException // OK—NullPointerException is an
unchecked exception
 ...
 
@Override
public void checkEven(Double number) throws OddNumberException // OK—identical to the superclass
 ...
 
class PrimeNumberException extends OddNumberException {}
class NonEvenNumberException extends OddNumberException {}
 
@Override
public void checkEven(int number) throws PrimeNumberException, NonEvenNumberException // OK—these are both subclasses
 
@Override
public void checkEven(Double number) throws IOExcepion // ERROR

The reason for this rule is that if an overridden method can throw a checked exception that the overridden method could not throw, that would break type substitutability.

Basic Programs