Exceptions: try, catch, finally
Exceptions, collections and modern Java11 min readLesson 1 of 6
1.1 When a statement fails
An exception is an object that represents a failure. When a method cannot continue, it throws an exception. The JVM looks for a matching catch block. If none is found, the program stops and prints a stack trace.
try holds the statements that may fail. catch names an exception type and receives the object. The catch block runs only for a matching type or a subclass of it.
The stack trace lists the calls that led to the failure. Read the first line for the exception type and message, then the frames for the method and line where it started.
public class Main {
public static void main(String[] args) {
int total = 10;
int parts = 0;
try {
System.out.println(total / parts);
} catch (ArithmeticException e) {
System.out.println("Cannot divide: " + e.getMessage());
}
}
}Output
Cannot divide: / by zero
1.1.1 Multiple catch blocks
A try can have several catch blocks. Java checks them in order, so put the specific type before a broader one. A catch for Exception after a catch for NumberFormatException is valid. The reverse makes the specific block unreachable.
A multi-catch combines unrelated types with |: catch (NumberFormatException | NullPointerException e). The variable is effectively final, and the block handles both.
Catch only what the code can handle. A catch that reports a bad input value and continues is fine for a form. A catch that hides a programming error makes the next failure harder to find.
public class Main {
public static void main(String[] args) {
String[] values = { "12", "x" };
for (String value : values) {
try {
System.out.println(Integer.parseInt(value));
} catch (NumberFormatException e) {
System.out.println("Bad number: " + value);
}
}
}
}Output
12 Bad number: x
1.1.2 finally
finally runs after the try block and any catch block, whether the try completed, threw, or returned. It is the place for cleanup that must happen on every path.
If a return sits in the try block, the finally block runs before the value is returned to the caller. A return inside finally would override the earlier return, which is why returns in finally are avoided.
A try can have finally without a catch. That form is useful when the method declares the exception and the cleanup still must run.
public class Main {
public static void main(String[] args) {
System.out.println(read());
}
static int read() {
try {
return 1;
} finally {
System.out.println("Cleanup");
}
}
}Output
Cleanup 1
1.1.3 Common runtime exceptions
NullPointerException means a method or field was used through a null reference. ArrayIndexOutOfBoundsException means an index was below 0 or at least the array length. NumberFormatException means text could not be parsed as a number. ArithmeticException covers integer division by zero.
These are unchecked, so the compiler does not require a catch. They usually point to a bug in the code. An expected condition is better handled with a check before the operation.
A message from the exception is useful in a log. Do not build user-facing text from it without control, because the wording can change between versions.
public class Main {
public static void main(String[] args) {
try {
Object value = "text";
int number = (Integer) value;
System.out.println(number);
} catch (ClassCastException | NullPointerException e) {
System.out.println(e.getClass().getSimpleName());
}
}
}Output
ClassCastException
1.1.4 Flow after a catch
After a catch block finishes, execution continues with the statement after the try statement. The statements remaining in the try block are skipped. Code that must run in both cases belongs after the try/catch or in finally.
A loop can catch an exception per pass and continue with the next value. That pattern suits a batch where one bad row should not stop the rest.
An uncaught exception ends the current thread. The main thread ending means the program exits with a nonzero status, which build tools and scripts can detect.
public class Main {
public static void main(String[] args) {
int[] values = { 4, 0, 2 };
for (int value : values) {
try {
System.out.println(10 / value);
} catch (ArithmeticException e) {
System.out.println("Skipped zero");
}
}
}
}Output
2 Skipped zero 5
1.1.5 Practice
- Divide by zero inside a try and print the exception message from the catch.
- Parse
"12"and"x"in a loop, catchingNumberFormatExceptionfor the bad value. - Add a finally block that prints
Cleanupand observe when it runs. - Use a multi-catch for a cast failure and a null access.
- Move a print statement from inside the try to after the catch and note which lines run after a failure.
For step 5, the skipped line should be visible in the output. That gap is how you can tell where execution resumed.
