Try-Catch
Overview
Exception Handling is one of the most critical real-world skills in Java development. An Exception is an unexpected event that disrupts the normal flow of a program — for example, reading a file that doesn't exist, dividing a number by zero, or receiving a null value where an object was expected.
In Java, exceptions are objects. Every exception inherits from the root Throwable class, which splits into two major branches: Errors (catastrophic JVM-level problems like OutOfMemoryError that you generally cannot recover from) and Exceptions (recoverable application-level problems). Exceptions are further split into Checked Exceptions (like IOException, which the compiler forces you to handle) and Unchecked/Runtime Exceptions (like NullPointerException, which the compiler doesn't force you to handle but which crash the program at runtime).
The try-catch-finally block is your safety net. Code inside the try block is executed normally. If any line inside it throws an exception, the JVM immediately jumps down to the matching catch block to handle it gracefully. The optional finally block always executes regardless of whether an exception occurred — it is designed for cleanup code like closing file streams or releasing database connections.
Syntax
The finally block is critical for resource cleanup. Whether the file was found or not, the cleanup code must always execute to prevent resource leaks.
import java.io.FileReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
// 1. Catching a Specific Exception
try {
int[] numbers = {1, 2, 3};
System.out.println(numbers[10]); // ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Caught: " + e.getMessage());
}
// 2. Multi-Catch Block (Java 7+)
try {
String s = null;
s.length(); // NullPointerException
} catch (NullPointerException | IllegalArgumentException e) {
System.out.println("Caught multi: " + e.getClass().getSimpleName());
}
// 3. The Finally Block — Always runs!
FileReader file = null;
try {
file = new FileReader("config.txt");
// ... read the file
} catch (IOException e) {
System.out.println("File not found!");
} finally {
// Cleanup: runs even if an exception occurred
System.out.println("Cleaning up resources...");
}
}
}Common Pitfalls
- Silently swallowing exceptions with empty catch blocks. Writing
catch (Exception e) { }is one of the most dangerous anti-patterns in Java. If your code crashes and you swallowed the exception, you have zero visibility into why. Always at minimum log the error withe.printStackTrace()or a proper logger. - Catching the root
ExceptionorThrowableclass too broadly. Writingcatch (Exception e)will intercept almost every exception in the program, including ones you never intended to catch. Always catch the most specific exception type possible. - Using try-catch for control flow logic. Exception handling has significant performance overhead compared to a simple
ifstatement. Do not writetry { Integer.parseInt(str); } catch(...) {}to check if a string is a number. Usestr.matches("\\d+")instead.
Interview Questions
A Checked Exception (like IOException, SQLException) is verified by the compiler. You MUST either handle it with a try-catch or declare it on the method signature with throws. An Unchecked Exception (like NullPointerException, ArrayIndexOutOfBoundsException) is a subclass of RuntimeException. The compiler does not force you to handle it, but it will crash the program at runtime if unhandled.
finally block does NOT execute?Yes, two rare cases. First, if System.exit() is called anywhere inside the try or catch blocks, the JVM immediately shuts down and the finally block is skipped. Second, if a fatal Error like OutOfMemoryError occurs and the JVM itself crashes, the finally block won't run.
finally block for I/O?Try-with-resources (try (FileReader f = new FileReader(path)) {}) automatically calls .close() on the resource when the block exits, whether by success or exception. It eliminates the boilerplate finally block and also properly handles the edge case where both the main code and the finally cleanup code throw exceptions simultaneously.
Real-World Example
In a production REST API (Spring Boot), every external network call — reading from a database, calling a payment gateway, parsing user JSON — must be wrapped in try-catch. Without this, a single bad request would crash the entire thread pool and take down the whole server for all users.
@RestController
public class UserController {
@GetMapping("/user/{id}")
public ResponseEntity<User> getUser(@PathVariable int id) {
try {
User user = db.findById(id); // Could throw SQLException
return ResponseEntity.ok(user);
} catch (UserNotFoundException e) {
return ResponseEntity.status(404).body(null);
} catch (SQLException e) {
log.error("DB error for user " + id, e);
return ResponseEntity.status(500).body(null);
}
}
}Check Your Knowledge
Test your understanding of Try-Catch with these quick questions.