Common runtime exceptions in Java
NPE, ClassCast, IllegalArgument, IllegalState, NumberFormat, IndexOutOfBounds, UnsupportedOperation, ConcurrentModification.
The bad-data family
NullPointerException: you used null. ClassCastException: an impossible cast. NumberFormatException: text that isn't a number. IndexOutOfBoundsException and its kids, like StringIndexOutOfBoundsException: an index past the end.
Integer.parseInt("abc"); // NumberFormat
String s = null;
s.length(); // NullPointer
"hi".charAt(5); // StringIndexOutOfBounds
Object o = 1;
String t = (String) o; // ClassCastThe API-misuse family
IllegalArgumentException: the value passed in is bad. IllegalStateException: the call is fine, but the object's state isn't — e.g. using it after it was closed. UnsupportedOperationException: this object doesn't support that operation. ConcurrentModificationException: a collection changed while being iterated.
Changing a fixed list
What happens?
List<String> tags = List.of("a", "b");
tags.add("c");
System.out.println(tags);[a, b, c]Compile errorThrows UnsupportedOperationException
Show the answer
List.of returns an unmodifiable list. The List interface has add (and set), so it compiles — but the implementation refuses at runtime.
Removing inside for-each
A for-each loop secretly uses an iterator. Removing through the list behind its back makes the next step fail fast with ConcurrentModificationException. Use nums.removeIf(n -> n == 1) instead.
List<Integer> nums =
new ArrayList<>(List.of(1, 2, 3));
for (Integer n : nums) {
if (n == 1) nums.remove(n); // throws
}Argument or state?
setDiscount(int percent) is called with 150. Which exception should it throw?
Think about it, then reveal the answer
IllegalArgumentException — the value passed in is out of range, so the argument is at fault. Throw it early with a clear message like "percent must be 0-100". IllegalStateException is for when the object's *current state* makes the call invalid.
Names point to fixes
In production logs, each name hints at the fix: NPE → validate earlier or handle the missing value; ConcurrentModificationException → removeIf or an iterator; UnsupportedOperationException → copy into a new ArrayList<>(...) before changing it.
Key takeaways
- IllegalArgumentException = bad input; IllegalStateException = wrong time/state
- List.of(...) is unmodifiable → UnsupportedOperationException on add/set
- Removing in a for-each loop → ConcurrentModificationException
- Helpful NPE messages (default since Java 15) name what was null
Since Java 15, NullPointerException messages name exactly what was null — like Cannot invoke "String.length()"… (added in Java 14, on by default in 15).
Practice questions
What does this print?
List<Integer> nums = List.of(1, 2, 3);
nums.set(0, 9);
System.out.println(nums);- [9, 2, 3]
- [1, 2, 3]
- Throws UnsupportedOperationException
- Compile error
Check your answer
Throws UnsupportedOperationException. List.of returns an unmodifiable list. The List interface allows set(), so it compiles, but the implementation refuses at runtime.
What does this print?
List<String> names =
new ArrayList<>(List.of("a", "b", "c"));
for (String n : names) {
if (n.equals("a")) names.remove(n);
}
System.out.println(names);- [b, c]
- Throws ConcurrentModificationException
- [a, b, c]
- Throws IndexOutOfBoundsException
Check your answer
Throws ConcurrentModificationException. The for-each loop uses an iterator. Removing through the list behind its back makes the iterator's next() fail fast.