Before the questions, make sure you can: draw the part of the exception hierarchy that matters
(Throwable, Error, Exception, RuntimeException); state the difference between
a checked and an unchecked exception and what the compiler demands of each; predict the exact
output of a try/catch/finally block, with and without an exception; order several
catch clauses correctly and say why the reverse order does not compile; read nested
try blocks; use throw and throws correctly; and write a custom exception class.
What an exception is
An exception is an object that represents an abnormal situation. When one is thrown, normal
execution stops and the JVM looks for a matching catch in the current method, then in its
caller, and so on up the call stack. If none is found, the program terminates and the stack trace
is printed.
Throwable |
the root of everything that can be thrown |
|---|---|
Error |
serious JVM problems (OutOfMemoryError); do not catch these |
Exception |
application problems; checked, except the branch below |
RuntimeException |
unchecked: NullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException, StringIndexOutOfBoundsException, NumberFormatException, InputMismatchException, ClassCastException, IllegalArgumentException |
- Checked exceptions (
IOException,FileNotFoundException,ParseException) must be handled or declared: either catch them, or addthrowsto the method heading. The compiler enforces this. - Unchecked exceptions (anything under
RuntimeException) need no declaration. They usually indicate a programming bug, and the right response is normally to fix the code rather than to catch it. - Unchecked does not mean fatal, and checked does not mean likely.
try, catch, finally
try {
int data = 100 / divisor; // statements that might throw
System.out.print("Try "); // SKIPPED if the line above throws
} catch (ArithmeticException e) {
System.out.print("Catch "); // runs only for a matching exception
} finally {
System.out.print("Finally "); // runs ALWAYS: exception or not, even after return
}
System.out.print("End");
Three behaviours to internalise:
- When an exception is thrown, the rest of the
tryblock is abandoned; control never comes back to it. - If a
catchhandles the exception, execution continues normally after the wholetrystatement. finallyruns in every case — normal completion, handled exception, unhandled exception, even an earlyreturn— which makes it the place to release resources.
Several catch clauses
Clauses are tried in order and the first matching one wins, so they must be written from the most specific to the most general:
try { ... }
catch (ArrayIndexOutOfBoundsException e) { System.out.print("Specific"); }
catch (Exception e) { System.out.print("General"); }
Reversing them does not compile: the specific clause would be unreachable. Since Java 7, a
multi-catch handles several unrelated types at once, and the parameter is implicitly final:
catch (NumberFormatException | ArithmeticException e) { ... } // legal
catch (Exception | ArithmeticException e) { ... } // ERROR: one is a subclass
Nested try blocks are resolved from the inside out: an inner catch that matches handles
the exception, and the outer block continues after the inner statement as if nothing had
happened.
throw and throws
public void setAge(int age) {
if (age < 0) throw new IllegalArgumentException("age must be >= 0"); // throw an object
this.age = age;
}
public void load(String file) throws IOException { ... } // declare: callers must deal with it
throw is a statement that raises one exception object now; throws is a clause in a
method heading that warns callers. A method may declare several, separated by commas.
Custom exceptions
public class TimeFormatException extends Exception { // checked: extends Exception
public TimeFormatException(String message) { super(message); }
}
public class MessageTooLongException extends RuntimeException { // unchecked
public MessageTooLongException(String message) { super(message); }
}
Extend Exception when the caller can reasonably be expected to recover and should be forced
to think about it; extend RuntimeException for programming errors. Pass the message to
super so that getMessage() works.
Good practice
Catch what you can actually handle; do not write an empty catch block; never catch
Exception simply to silence the compiler; keep try blocks small; and close resources in
finally or, better, with try-with-resources:
try (Scanner in = new Scanner(new File("data.txt"))) { ... }.
- Checked = handle or declare; unchecked =
RuntimeExceptionand its subclasses. - The rest of the
tryblock is skipped once something is thrown. finallyalways runs.- Specific
catchclauses come before general ones. throwraises;throwsdeclares.- A custom checked exception extends
Exception; an unchecked one extendsRuntimeException.
catch (Exception e)first, making later clauses unreachable.- Expecting statements after the failing line inside
tryto run. - Catching
NullPointerExceptioninstead of testing fornull. - Declaring
throwson a method whose body cannot throw a checked exception (legal but misleading), or forgetting it when it can (a compile error).
Ready? Close the notes and practise.
38 questions. Predict the output before you check — that is the skill the exam measures.