Handbooks / Java / Chapter 3

Exceptions

7 pages · ~4 min✓ Reviewed

Builds on Collections Framework. Next up: JVM and Memory.

JavaPage 1

Exception Mental Model

1. Throwable Hierarchy

  • Error = JVM failures like OutOfMemoryError; do not catch
  • Everything under Exception except RuntimeException is checked

2. Checked vs Unchecked

CheckedUnchecked
ExtendsException, not RuntimeExceptionRuntimeException or Error
Compilerforces catch or declareno enforcement
ExamplesIOException, SQLExceptionNullPointerException, IllegalArgumentException
Use forrecoverable conditionsprogramming bugs

3. Common Mistake

  • Catching Throwable or Exception swallows Errors and bugs
  • Catch the most specific type
Rule of thumb

Caller can recover → checked. Caller cannot fix it, it is a bug → unchecked.

JavaPage 2

try, catch and finally Flow

1. Syntax and Catch Order

  • try needs at least one catch or finally
  • Catch blocks are checked top to bottom: first matching type wins
  • Subclass before superclass, or compile error
java
try { read(); }
catch (FileNotFoundException e) { }
catch (IOException e) { }
finally { cleanup(); }

subclass first, superclass after

2. Multi-catch and finally

  • catch (IOException | SQLException e) handles unrelated types
  • e is implicitly final
  • Types cannot be related by inheritance
  1. tryrisky code
  2. catchonly if matching
  3. finallyalways runs
  • finally runs with or without an exception, even after return
  • Skipped only by System.exit() or a JVM crash

3. Common Mistake

No return or throw in finally

It overrides the try result and silently discards the original exception.

JavaPage 3

try-with-resources

1. Syntax and Close Order

  • Auto-closes any AutoCloseable declared in try (...)
  • Closes in reverse order of declaration
  • Closing happens before any catch or finally
java
try (BufferedReader br =
     new BufferedReader(new FileReader(f))) {
    return br.readLine();
} catch (IOException e) {
    handle(e);
}
  1. Body
  2. close()reverse order
  3. catch
  4. finally

2. Suppressed and Java 9

  • Body and close() both throw: body exception is primary
  • Close exception attached via getSuppressed()
  • Java 9+: effectively final variable works: try (res) { ... }

3. Mistake and Interview Point

  • Manual finally { close() }: verbose, and a failing close() can hide the original exception
  • What is a suppressed exception? A close() error kept on the primary one
  • Close order? Reverse of declaration, before catch
  • Why prefer it over finally? Shorter, never loses the original error
JavaPage 4

throw vs throws and Custom Exceptions

1. throw vs throws

throwthrows
Is astatementsignature clause
Takesone exception objectexception types (required for checked)
Wheremethod bodyafter the parameter list
Examplethrow new IllegalStateException("msg")void read() throws IOException

2. Custom Exceptions

  • Checked: class AppException extends Exception
  • Unchecked: extends RuntimeException
  • Provide (message) and (message, cause) constructors
  • Wrap lower-level errors, keep the cause
java
class AppException extends Exception {
  AppException(String m, Throwable c) { super(m, c); }
}
try { load(); }
catch (IOException e) {
  throw new AppException("load failed", e);
}

wrap and rethrow

3. Overriding Rules

  • Override cannot throw a broader checked exception than the parent
  • It may throw fewer, narrower, or any unchecked exception
  • Parent throws IOException, child throws Exception → compile error
Keep the cause

Always pass e when wrapping, or the original stack trace is lost.

JavaPage 5

Common Runtime Exceptions

1. Causes and Guards

ExceptionCauseGuard
NullPointerExceptionmethod or field on nullnull check, Objects.requireNonNull, Optional
ArrayIndexOutOfBoundsException (is an IndexOutOfBoundsException)index < 0 or >= lengthvalid range 0 to length-1
ClassCastExceptioninvalid downcastinstanceof before cast
NumberFormatException (is an IllegalArgumentException)Integer.parseInt("abc")validate input
ArithmeticExceptionint divide by zerocheck divisor
ConcurrentModificationExceptionremove inside for-eachIterator.remove(), removeIf

2. Safe Removal

  • Use removeIf instead of list.remove inside a for-each loop
java
List<Integer> l = new ArrayList<>(List.of(1, 2, 3));
l.removeIf(n -> n == 2);
System.out.println(l);
output
[1, 3]

3. Remember

Int vs double

5 / 0 throws ArithmeticException, but 5.0 / 0 gives Infinity.

  • Interview: why is 5.0 / 0 no exception? Floating point defines Infinity; only int division throws.
  • Interview: how to remove while looping? Iterator.remove() or removeIf.
JavaPage 6

Exceptions Cheat Sheet

1. Hierarchy

  1. 1Throwableroot
  2. 2ErrorJVM, unchecked
  3. 3Exceptionchecked
  4. 4RuntimeExceptionunchecked

2. Order and keywords

  1. try
  2. Resources close
  3. Matching catch
  4. finally
KeywordDoes
throwraises an object
throwsdeclares in signature
finallyalways cleans up
try(...)auto-closes

3. Best practice

  • Catch specific types
  • Never swallow with an empty catch
  • Wrap with the cause: new AppException(msg, e)
Mistake

return or throw in finally discards the original exception.

4. Interview Point

  • Checked vs unchecked? Compiler forces catch or declare vs no enforcement
  • finally after return? Yes; skipped only by System.exit()
  • Suppressed exception? close() error attached via getSuppressed()
  • Broader throws on override? No; fewer or unchecked only
JavaPage 7

Check yourself

What does this print?
  • F, then 1
  • finally runs before the method returns, so F prints first
static int f() {
  try { return 1; }
  finally { System.out.println("F"); }
}
System.out.println(f());
Why does this not compile?
  • Exception already catches IOException, so the second catch is unreachable
  • Put the subclass first
try { read(); }
catch (Exception e) { }
catch (IOException e) { }
In try-with-resources, the body throws A and close() throws B. Which does the caller see?
  • A, with B attached through getSuppressed()
  • A manual finally { close() } would throw B and lose A