Skip to main content

Exceptions

Source: Effective Java, 3rd Edition — Chapter 10 by Joshua Bloch (Items 69–73)

Used well, exceptions improve readability and reliability. Used as control flow or leaked implementation details, they do the opposite. This lesson: when to throw, checked vs unchecked, standard types, and exception translation.

Item 69: Use exceptions only for exceptional conditions​

Never loop by catching ArrayIndexOutOfBoundsException or NoSuchElementException — it’s obscure, slow, and can swallow unrelated bugs.

// Don't
try {
int i = 0;
while (true)
range[i++].climb();
} catch (ArrayIndexOutOfBoundsException ignored) { }

// Do
for (Mountain m : range)
m.climb();

APIs should offer state-testing methods (Iterator.hasNext) or Optional (Item 55) so clients aren’t forced into exception-driven control flow.

Quiz

Exceptions vs control flow

1 / 2

Iterator lacks hasNext(); clients catch NoSuchElementException to end loops

Pick an answer to see if you are right.

Item 70: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors​

Three throwable families:

KindWhenCaller expectation
Checked (Exception subclass, not RuntimeException)Recoverable conditionsHandle or declare
Runtime (RuntimeException)Programming errors, precondition violationsUsually don’t catch
ErrorJVM/resource catastropheDon’t throw new subclasses

ArrayIndexOutOfBoundsException = bad index (client bug). Insufficient funds on gift card = checked exception with recovery info (e.g. shortfall amount).

When unsure, prefer unchecked. Don’t define throwables outside Exception / RuntimeException / Error. Never parse exception strings for data — add accessor methods on checked exceptions.

Quiz

Checked vs unchecked

1 / 2

Method rejects null where null is forbidden

Pick an answer to see if you are right.

Item 71: Avoid unnecessary use of checked exceptions​

Checked exceptions force handling — good when recovery is real, painful when callers only do printStackTrace() or throw new AssertionError().

Remedies:

  1. Return Optional.empty() instead of throwing when absence is ordinary (Item 55).
  2. Split into actionPermitted + action so the happy path need not sit in try (watch concurrency and duplicated work).

Single checked exceptions are especially costly — they block stream usage (Items 45–48).

Item 72: Favor the use of standard exceptions​

Reuse library exceptions when semantics match:

ExceptionUse when
IllegalArgumentExceptionBad non-null argument value
IllegalStateExceptionObject state wrong for this call
NullPointerExceptionNull where prohibited
IndexOutOfBoundsExceptionBad index into sequence
ConcurrentModificationExceptionDetected unsynchronized mutation
UnsupportedOperationExceptionOptional operation not implemented

Don’t throw Exception, RuntimeException, Throwable, or Error directly — too broad to catch meaningfully.

Deck deal example: hand size too big because deck is nearly empty → IllegalStateException if no argument would work; IllegalArgumentException if a smaller hand size would work.

Quiz

Standard exceptions

1 / 2

Append-only List.remove(index) is invoked

Pick an answer to see if you are right.

Item 73: Throw exceptions appropriate to the abstraction​

Don’t leak low-level exceptions (NoSuchElementException from a ListIterator) through high-level APIs. Translate to types your abstraction promises:

public E get(int index) {
ListIterator<E> i = listIterator(index);
try {
return i.next();
} catch (NoSuchElementException e) {
throw new IndexOutOfBoundsException("Index: " + index);
}
}

Use exception chaining (new HigherLevelException(cause)) so debuggers still see the root cause via getCause(). When you can prevent lower-level failures (validate parameters) or recover silently (log and continue), prefer that over translation.

Items 69–73 map​

ItemMove
69Exceptions for failures, not loops; hasNext / Optional
70Checked = recoverable; runtime = precondition bugs
71Optional or state-test to avoid pointless checked exceptions
72Reuse IllegalArgumentException, IllegalStateException, …
73Translate lower-level exceptions to abstraction-level types

Next: Exception Documentation and Handling (Items 74–77).