try, catch and finally in Java
try guards a block, catch handles specific failures, finally always runs, and try with resources closes what you opened.
-
Java Basics
- Introduction to Java
- Setting Up Java and Writing Your First Program
- Variables, Data Types and Literals in Java
- Type Casting and Type Conversion in Java
- Operators and Expressions in Java
- Input and Output in Java
- Comments, Keywords and Naming Conventions in Java
- Control Flow in Java: if, else and switch
- Loops in Java: for, while and do-while
- Methods
- Arrays and Strings
-
OOP
- Classes and Objects in Java
- Constructors in Java
- The this Keyword in Java
- The static Keyword in Java
- Encapsulation in Java
- Access Modifiers in Java
- Inheritance in Java
- Method Overriding and super in Java
- Polymorphism in Java
- Abstraction, Abstract Classes and Interfaces in Java
- Composition, Aggregation and Association in Java
- The Object Lifecycle in Java
- Core Java
- Exception Handling
-
Collections
- The Java Collections Framework
- List in Java: ArrayList, LinkedList, Vector and Stack
- Set in Java: HashSet, LinkedHashSet and TreeSet
- Map in Java: HashMap, LinkedHashMap and TreeMap
- How HashMap Works Internally in Java
- Queue and Deque in Java: ArrayDeque and PriorityQueue
- Iterators in Java
- Comparable and Comparator in Java
- Collections Utilities and Choosing the Right Collection
- Generics
- Java 8+
- Stream API
- Date and Time
- File and I/O
-
Multithreading
- Threads in Java: Processes, Runnable and Thread
- Thread Lifecycle in Java
- Synchronization in Java: synchronized and volatile
- Locks and Atomic Classes in Java
- Race Conditions and Deadlocks in Java
- The Executor Framework and Thread Pools in Java
- Future and CompletableFuture in Java
- Concurrent Collections in Java
- The Java Memory Model
- JVM and Memory
- Advanced Java
- Networking
- JDBC
- Testing
The basic form
try {
int value = Integer.parseInt(input);
System.out.println(100 / value);
} catch (NumberFormatException e) {
System.out.println("That was not a number: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero");
} finally {
System.out.println("This always runs");
}tryencloses the code that might fail.- Each
catchhandles one type, and the first matching block runs. finallyruns whether or not an exception occurred.
Catch order matters
try {
load();
} catch (IOException e) { // specific first
recover();
} catch (Exception e) { // general second
report(e);
}
// Reversed, the compiler rejects it: the IOException block would be unreachableMulti catch
try {
process(path);
} catch (IOException | IllegalArgumentException e) {
logger.warning("Could not process: " + e.getMessage());
}When two types deserve the same handling, list them together. The parameter is implicitly final, and its static type is the nearest common supertype.
finally
Connection connection = null;
try {
connection = open();
connection.execute(sql);
} catch (SQLException e) {
logger.severe("Query failed");
} finally {
if (connection != null) {
connection.close(); // runs on success, on failure and on return
}
}finally runs even when the try block executes a return. The only cases where it does not run are a JVM exit through System.exit, or the thread or process being killed.
The finally return trap
static int surprising() {
try {
return 1;
} finally {
return 2; // discards the value above, and swallows any exception
}
}
// surprising() returns 2Neverreturn,breakorthrowfrom afinallyblock. It silently overrides the result and can hide an exception that was on its way out.
try with resources
try (BufferedReader reader = Files.newBufferedReader(path);
BufferedWriter writer = Files.newBufferedWriter(output)) {
String line;
while ((line = reader.readLine()) != null) {
writer.write(line.strip());
writer.newLine();
}
} catch (IOException e) {
logger.severe("Copy failed: " + e.getMessage());
}Any resource implementing AutoCloseable declared in the header is closed automatically, in reverse order of creation, whether the block succeeds or fails. This replaced the error prone finally pattern above and should be used for every closeable resource.
Suppressed exceptions
try (var resource = open()) {
resource.use(); // throws A
} // close() throws B
// A propagates; B is attached and available from getSuppressed()Before try with resources, an exception thrown by close() would replace the real failure. Now the original wins and the secondary one is preserved rather than lost.
Effectively final resources
BufferedReader reader = Files.newBufferedReader(path);
try (reader) { // allowed since Java 9 for an effectively final variable
return reader.readLine();
}Nested try blocks
try {
for (String row : rows) {
try {
process(row);
} catch (IllegalArgumentException e) {
logger.warning("Skipping row: " + row); // continue with the next row
}
}
} catch (IOException e) {
logger.severe("Could not read the source"); // abandon everything
}The inner block handles a per item failure and keeps going; the outer one handles a failure that ends the whole operation. Choosing the right scope for a try block is most of the skill.
Catching and rethrowing
try {
repository.save(note);
} catch (SQLException e) {
throw new StorageException("Could not save note " + note.id(), e); // keep the cause
}Always pass the original exception as the cause. Dropping it loses the stack trace that explains what really happened.
Common mistakes
- An empty
catchblock. A failure occurs, nothing is recorded, and the bug becomes invisible. - Catching
Exceptionwhen only one type was expected. - Wrapping an exception without passing the cause.
- Returning from
finally. - Closing resources manually when try with resources would do it correctly.
- Wrapping a
tryaround a hundred lines, so it is unclear which one can fail.
Best practices
- Keep the
tryblock as small as the code that can actually fail. - Catch the most specific type that you can genuinely handle.
- Use try with resources for anything closeable.
- Log or rethrow, but never silently swallow.
- Preserve the cause when wrapping.
Practice
- Predict the output of a method that returns 1 in
tryand 2 infinally. - Rewrite a
finallybased file close as try with resources. - Why will
catch (Exception e)beforecatch (IOException e)not compile? - Write a loop that skips bad rows but stops on a read failure.
- Show what
getSuppressed()returns when both the body andclose()throw.
Conclusion
Catch what you can handle, keep the guarded block small, use try with resources for anything that must be closed, and never let a finally block change the outcome.