Common Exceptions in Java: Causes and How to Fix Them - Quiz
Total: 4 questions
1. How do you read a NullPointerException message in Java 15+ and how do you fix this exception?
How do you read a NullPointerException message in Java 15+ and how do you fix this exception?
Since Java 15 the message (helpful NullPointerException, JEP 358) names the operation and the expression that was null: Cannot invoke "String.length()" because "name" is null. For auto-unboxing (int n = map.get("x");) it says because the return value of "java.util.Map.get(Object)" is null. If the class was compiled by javac without the -g flag, a slot number such as "<local1>" appears instead of the local variable name; IDEs, Maven and Gradle compile with debug information and show the real name. Java 8 and 11 print no message, only the line number in the stack trace. NPE is fixed by changing the code, not with catch: if the value must be there, initialize the reference; if it may legitimately be missing, use getOrDefault() instead of get(), put the constant first in "London".equals(city), use Objects.requireNonNullElse(value, default) or an explicit if (x != null) check.
2. Why does ClassCastException occur only at run time, and how do you avoid it?
Why does ClassCastException occur only at run time, and how do you avoid it?
The compiler allows a cast if the static type of the variable (Object, a superclass, an interface) could in principle hold the target type; the actual class of the object is checked only at run time. So Object value = 42; String s = (String) value; compiles but fails with class java.lang.Integer cannot be cast to class java.lang.String: the first class is the real class of the object, the second is the type it was cast to. A cast between clearly incompatible types, such as (String) 42, does not compile at all. The exception can also appear without an explicit cast: if a number gets into a List<String> through the raw type List, the compiler inserts a cast when the element is read, and the error shows up there, far from its cause. To avoid it, check the type before casting — since Java 16 in a single construct if (a instanceof Dog dog) { dog.bark(); } — do not use raw types, and do not ignore unchecked warnings.
3. What is the difference between IllegalArgumentException and IllegalStateException, and which JDK methods throw them?
What is the difference between IllegalArgumentException and IllegalStateException, and which JDK methods throw them?
IllegalArgumentException means the method received an invalid argument value: new ArrayList<>(-1) (Illegal Capacity: -1), "ab".repeat(-1), DayOfWeek.valueOf("monday") (No enum constant java.time.DayOfWeek.monday — the constant name is case-sensitive). Its subclass is NumberFormatException. It is fixed by normalizing the data before the call, for example valueOf(input.strip().toUpperCase(Locale.ROOT)). IllegalStateException means the arguments are fine, but the object is in the wrong state — the error is in the order of calls: a second terminal operation on the same Stream (stream has already been operated upon or closed), nextLine() on a closed Scanner (Scanner closed), matcher.group() before a successful find(), iterator.remove() before next(). It is fixed by following the object lifecycle: for example, keep the data in a collection and create a new stream for each operation.
4. Why does ConcurrentModificationException occur, and how do you correctly remove elements from a collection while iterating?
Why does ConcurrentModificationException occur, and how do you correctly remove elements from a collection while iterating?
The iterator of ArrayList, HashMap and other java.util collections remembers the modification counter (modCount). If you call list.remove() or list.add() on the same list inside a for-each loop, the next iterator.next() notices the mismatch and throws ConcurrentModificationException with no message — that is why the stack trace points to the loop header, not to the line with remove(). The check is best-effort (fail-fast): after removing the second-to-last element the loop simply ends without an exception and the last element is never checked, so the absence of an exception does not prove the code is correct. Remove elements with list.removeIf(name -> name.startsWith("A")) (Java 8+) or with the iterator’s own remove(); for a HashMap use map.entrySet().removeIf(...). Despite the name, the error happens in a single thread too; for real multithreading use CopyOnWriteArrayList or ConcurrentHashMap.