Java Notes
Complete guide to the finally block in Java — guaranteed execution, resource cleanup, try-catch-finally flow, try-with-resources (Java 7+), and edge cases where finally may not execute.
What is the Finally Block?
The finally block is a block of code that always executes regardless of whether an exception occurs or not. It's the guaranteed cleanup mechanism in Java's exception handling.
Why Finally Exists
Without finally, resources might leak:
Basic Syntax
try {
// Risky code
} catch (ExceptionType e) {
// Handle exception
} finally {
// ALWAYS executes (cleanup code)
// Close files, connections, release locks, etc.
}All Execution Scenarios
Scenario 1: No Exception Occurs
public class FinallyNoException {
public static void main(String[] args) {
try {
System.out.println("1. Try block - start");
int result = 10 / 2;
System.out.println("2. Try block - result: " + result);
} catch (ArithmeticException e) {
System.out.println("3. Catch block (SKIPPED)");
} finally {
System.out.println("4. Finally block - ALWAYS runs");
}
System.out.println("5. After try-catch-finally");
}
}Output:
Scenario 2: Exception Occurs and is Caught
public class FinallyWithException {
public static void main(String[] args) {
try {
System.out.println("1. Try block - start");
int result = 10 / 0; // Exception!
System.out.println("2. Try block - SKIPPED");
} catch (ArithmeticException e) {
System.out.println("3. Catch block - " + e.getMessage());
} finally {
System.out.println("4. Finally block - ALWAYS runs");
}
System.out.println("5. After try-catch-finally");
}
}Output:
Scenario 3: Exception Occurs but NOT Caught
public class FinallyUncaughtException {
public static void main(String[] args) {
try {
System.out.println("1. Try block - start");
int result = 10 / 0; // ArithmeticException
System.out.println("2. SKIPPED");
} catch (NullPointerException e) { // Won't catch ArithmeticException!
System.out.println("3. Catch block - SKIPPED");
} finally {
System.out.println("4. Finally block - STILL runs!");
}
System.out.println("5. NEVER REACHED");
}
}Output:
Key Point: Finally executes even when the exception is NOT caught!
Scenario 4: Return Statement in Try Block
public class FinallyWithReturn {
public static void main(String[] args) {
System.out.println("Result: " + getValue());
}
static int getValue() {
try {
System.out.println("Try: returning 10");
return 10; // Return value is "remembered"
} catch (Exception e) {
System.out.println("Catch");
return 20;
} finally {
System.out.println("Finally: I still execute!");
// Note: Don't put return here (see below why)
}
}
}Output:
| Try | returning 10 |
| Finally | I still execute! |
| Result | 10 |
Important: The return value (10) is computed and saved, then finally runs, then the saved value is returned.
Scenario 5: Return in Finally (DON'T DO THIS!)
public class FinallyReturnDanger {
public static void main(String[] args) {
System.out.println("Result: " + getValue());
}
static int getValue() {
try {
System.out.println("Try: returning 10");
return 10;
} finally {
System.out.println("Finally: returning 99 (overrides!)");
return 99; // ⚠️ OVERRIDES try's return value!
}
}
}Output:
| Try | returning 10 |
| Finally | returning 99 (overrides!) |
| Result | 99 |
WARNING: A return in finally overrides the return in try or catch. This is a dangerous practice and should NEVER be done!
Execution Flow Diagram
Real-World Example: File Resource Cleanup
import java.io.FileWriter;
import java.io.IOException;
public class FileCleanup {
public static void main(String[] args) {
FileWriter writer = null;
try {
writer = new FileWriter("output.txt");
writer.write("Hello, World!\n");
writer.write("This is line 2\n");
// Simulate an error mid-write
if (true) {
throw new RuntimeException("Simulated error!");
}
writer.write("This line won't be written\n");
} catch (IOException e) {
System.out.println("Write error: " + e.getMessage());
} catch (RuntimeException e) {
System.out.println("Runtime error: " + e.getMessage());
} finally {
// CLEANUP: Close the file regardless of success/failure
System.out.println("Finally: Closing file writer...");
if (writer != null) {
try {
writer.close();
System.out.println("Finally: File writer closed successfully");
} catch (IOException e) {
System.out.println("Finally: Error closing writer: " + e.getMessage());
}
}
}
System.out.println("Program continues...");
}
}Output:
| Runtime error | Simulated error! |
| Finally | Closing file writer... |
| Finally | File writer closed successfully |
Real-World Example: Database Connection
Output:
| Test 1 | Successful query |
| [DB] Executing | SELECT * FROM users |
| Test 2 | Failed query |
| [DB] Executing | INSERT ERROR INTO table |
| [APP] Error | SQL Error in query: INSERT ERROR INTO table |
Try-With-Resources (Java 7+)
The try-with-resources statement is a modern alternative that automatically closes resources. Any class implementing AutoCloseable or Closeable can be used.
Traditional Way (Pre-Java 7)
import java.io.*;
public class TraditionalWay {
public static void main(String[] args) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("data.txt"));
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
System.out.println("Error closing: " + e.getMessage());
}
}
}
}
}Line 1 of file Line 2 of file (Resource closed in finally block)
Modern Way (Java 7+ Try-With-Resources)
import java.io.*;
public class ModernWay {
public static void main(String[] args) {
// Resource declared in try() — automatically closed!
try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
// No finally needed! reader.close() is called automatically
}
}Line 1 of file Line 2 of file (Resource auto-closed by try-with-resources)
Multiple Resources
import java.io.*;
public class MultipleResources {
public static void main(String[] args) {
// Multiple resources — closed in REVERSE order
try (FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt");
BufferedInputStream bis = new BufferedInputStream(fis)) {
int data;
while ((data = bis.read()) != -1) {
fos.write(data);
}
System.out.println("File copied successfully!");
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
// All three streams closed automatically (in reverse: bis, fos, fis)
}
}File copied successfully! (Both reader and writer auto-closed)
Custom AutoCloseable Class
Output:
Notice: Resources are closed in reverse order of creation (LIFO — Last In, First Out).
When Does Finally NOT Execute?
There are rare cases where finally won't execute:
public class FinallyNotExecuted {
public static void main(String[] args) {
// Case 1: System.exit() is called
try {
System.out.println("Before System.exit()");
System.exit(0); // JVM terminates immediately
} finally {
System.out.println("This will NOT print!");
}
// Case 2: JVM crashes (out of memory, segfault)
// Case 3: Infinite loop in try/catch
// Case 4: Thread is killed (Thread.stop() - deprecated)
// Case 5: Power failure / OS kills the process
}
}Output:
Finally with Exception in Catch Block
public class FinallyExceptionInCatch {
public static void main(String[] args) {
try {
try {
System.out.println("1. Try block");
throw new ArithmeticException("original");
} catch (ArithmeticException e) {
System.out.println("2. Catch block");
throw new RuntimeException("from catch"); // Exception in catch!
} finally {
System.out.println("3. Finally STILL executes!");
}
} catch (RuntimeException e) {
System.out.println("4. Outer catch: " + e.getMessage());
}
}
}Output:
Common Mistakes
1. Returning in Finally
// ❌ NEVER return from finally
static int bad() {
try {
throw new RuntimeException("error");
} catch (RuntimeException e) {
throw e; // This throw is LOST!
} finally {
return 0; // Swallows the exception! Bug!
}
}2. Not handling exceptions in finally
// ❌ BAD: Exception in finally masks the original
try {
throw new RuntimeException("original error");
} finally {
throw new RuntimeException("finally error");
// Original exception is LOST! Only "finally error" propagates
}3. Complex logic in finally
// ❌ BAD: Keep finally simple
finally {
if (condition1) {
// complex logic
} else if (condition2) {
// more complex logic
for (...) { ... }
}
}
// ✅ GOOD: finally should only do cleanup
finally {
closeQuietly(connection);
closeQuietly(stream);
}Best Practices
- Use try-with-resources whenever possible (Java 7+)
- Keep finally blocks short — only cleanup code
- Never return from finally — it overrides try/catch returns
- Never throw from finally — it masks the original exception
- Use helper methods for cleanup logic in finally
- Null-check resources before closing in finally
- Handle close() exceptions in finally (or use try-with-resources)
Interview Questions
Q1: Will the finally block execute if there's a return in try?
Answer: Yes! The finally block executes even if the try block has a return statement. The return value is computed and saved, finally runs, then the saved value is returned. However, if finally also has a return, it overrides the try's return.
Q2: When does finally NOT execute?
Answer: (1) When System.exit() is called, (2) JVM crashes, (3) the thread is killed/interrupted fatally, (4) infinite loop in try/catch that never completes, (5) hardware failure.
Q3: What is try-with-resources?
Answer: Introduced in Java 7, it's a try statement that declares resources (implementing AutoCloseable) in parentheses. These resources are automatically closed when the try block exits, eliminating the need for explicit finally blocks for resource cleanup.
Q4: Can we have try-finally without catch?
Answer: Yes! try { } finally { } is valid. The exception (if any) propagates to the caller, but finally still executes before propagation.
Q5: In what order are resources closed in try-with-resources?
Answer: Resources are closed in reverse order of their declaration (LIFO). If resource A is declared first and B second, B is closed first, then A.
Q6: What happens if both try and finally throw exceptions?
Answer: The exception from finally propagates, and the exception from try is lost (suppressed). In try-with-resources, suppressed exceptions are accessible via getSuppressed() method on the primary exception.
Q7: Difference between finally and finalize()?
Answer: finally is a block in exception handling that always executes for cleanup. finalize() is a method in Object class called by garbage collector before destroying an object (deprecated since Java 9). They serve completely different purposes.
Q8: What is the difference between finally and finalize()?
A: finally is a block that executes after try/catch regardless of exceptions — used for cleanup. finalize() is a deprecated Object method called by GC before reclaiming memory — unreliable timing, unpredictable behavior. They are completely unrelated concepts despite similar names. Never use finalize(); use try-with-resources instead.
Q9: Can finally block be skipped?
A: In rare cases: (1) System.exit() is called in try/catch block, (2) JVM crashes or is killed (kill -9), (3) Infinite loop or deadlock in try block that prevents reaching finally, (4) The thread running try-catch is a daemon thread and all user threads finish. In normal operation, finally ALWAYS executes.
Q10: What is try-with-resources and how does it replace finally?
A: Try-with-resources (Java 7+) automatically closes resources implementing AutoCloseable when the try block exits: try (FileReader fr = new FileReader("f")) { ... }. It replaces manually closing in finally, handles the case where close() itself throws, and uses suppressed exceptions for multiple failures.
Q11: If both try and finally have return statements, which one wins?
A: The finally block's return statement wins — it overwrites the try block's return value. This is considered bad practice because it silently discards the try block's result (and any exception). Never put return statements in finally blocks.
Q12: How does finally interact with System.exit()?
A: System.exit(int) terminates the JVM immediately. If called inside try or catch, the finally block does NOT execute. The JVM shutdown hooks may run, but finally blocks in the current stack are skipped. This is one of the very few cases where finally doesn't execute.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Finally Block in Java.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Java Master Course topic.
Search Terms
java-master-course, java master course, java, master, course, exception, handling, finally
Related Java Master Course Topics