Home/Java/Finally Block in Java

Finally Block in Java

Learn how to execute code that always runs, no matter what

💡 Think of finally like always washing your hands after eating - no matter what happens during the meal (you drop your food, you finish early, you spill something), you ALWAYS wash your hands at the end! Finally always executes!

🔒 What is Finally?

The finally block is a section of code that always executes after a try-catch block, regardless of whether an exception was thrown or caught. It's perfect for cleanup tasks like closing files or database connections.

BasicFinally.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class BasicFinally {
public static void main(String[] args) {
System.out.println("Program started");
try {
System.out.println("1. Inside try block");
int result = 10 / 2; // No exception
System.out.println("2. Result: " + result);
} catch (ArithmeticException e) {
System.out.println("3. Inside catch block");
System.out.println(" Error: " + e.getMessage());
} finally {
// This ALWAYS runs!
System.out.println("4. Inside finally block");
System.out.println(" This always executes!");
}
System.out.println("5. Program ended");
}
}
// Output:
// Program started
// 1. Inside try block
// 2. Result: 5
// 4. Inside finally block
// This always executes!
// 5. Program ended
// Note: catch didn't run because no exception occurred,
// but finally STILL ran!

🔍 📋 Execution Order

Understanding when finally executes:

1

Try Block Runs

Code in try block starts executing

2

Exception or Success

Either an exception occurs or code completes normally

3

Catch Block (if exception)

Catch block handles the exception if one occurred

4

Finally ALWAYS Runs

Finally block executes no matter what happened above

ExecutionOrder.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class ExecutionOrder {
public static void main(String[] args) {
System.out.println("=== Test 1: No Exception ===");
testFinally(10, 2);
System.out.println("\n=== Test 2: With Exception ===");
testFinally(10, 0);
}
public static void testFinally(int a, int b) {
try {
System.out.println("Step 1: Try block starts");
int result = a / b;
System.out.println("Step 2: Result = " + result);
} catch (ArithmeticException e) {
System.out.println("Step 3: Catch block");
System.out.println(" Caught: " + e.getMessage());
} finally {
System.out.println("Step 4: Finally block");
System.out.println(" This ALWAYS runs!");
}
System.out.println("Step 5: After try-catch-finally");
}
}
// Output:
// === Test 1: No Exception ===
// Step 1: Try block starts
// Step 2: Result = 5
// Step 4: Finally block
// This ALWAYS runs!
// Step 5: After try-catch-finally
//
// === Test 2: With Exception ===
// Step 1: Try block starts
// Step 3: Catch block
// Caught: / by zero
// Step 4: Finally block
// This ALWAYS runs!
// Step 5: After try-catch-finally

📁 Real-World Example: File Handling

FileHandling.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class FileHandling {
public static void main(String[] args) {
readFile("data.txt");
}
public static void readFile(String filename) {
BufferedReader reader = null;
try {
System.out.println("Opening file: " + filename);
reader = new BufferedReader(new FileReader(filename));
String line;
int lineNumber = 1;
while ((line = reader.readLine()) != null) {
System.out.println("Line " + lineNumber + ": " + line);
lineNumber++;
}
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
} finally {
// Cleanup: ALWAYS close the file
System.out.println("\nCleaning up...");
if (reader != null) {
try {
reader.close();
System.out.println("File closed successfully!");
} catch (IOException e) {
System.out.println("Error closing file: " + e.getMessage());
}
}
}
System.out.println("Operation complete!");
}
}
// Key points:
// 1. Finally ensures file is closed even if error occurs
// 2. Prevents resource leaks
// 3. Cleanup code runs whether exception occurred or not
// 4. This is a common pattern for resource management

💾 Real-World Example: Database Connection

DatabaseConnection.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Simulated database connection example
class DatabaseConnection {
private String connectionString;
private boolean isOpen = false;
public DatabaseConnection(String connectionString) {
this.connectionString = connectionString;
}
public void open() throws Exception {
System.out.println("Opening connection: " + connectionString);
if (connectionString.equals("invalid")) {
throw new Exception("Invalid connection string!");
}
isOpen = true;
System.out.println("Connection opened!");
}
public void executeQuery(String query) {
System.out.println("Executing: " + query);
if (query.contains("ERROR")) {
throw new RuntimeException("Query failed!");
}
System.out.println("Query successful!");
}
public void close() {
if (isOpen) {
System.out.println("Closing connection...");
isOpen = false;
System.out.println("Connection closed!");
}
}
}
public class DatabaseExample {
public static void main(String[] args) {
System.out.println("=== Test 1: Successful Query ===");
performQuery("localhost:3306", "SELECT * FROM users");
System.out.println("\n=== Test 2: Failed Query ===");
performQuery("localhost:3306", "SELECT * ERROR FROM users");
System.out.println("\n=== Test 3: Connection Failed ===");
performQuery("invalid", "SELECT * FROM users");
}
public static void performQuery(String connectionString, String query) {
DatabaseConnection conn = new DatabaseConnection(connectionString);
try {
conn.open();
conn.executeQuery(query);
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
} finally {
// ALWAYS close the connection
System.out.println("\n[Finally Block]");
conn.close();
}
System.out.println("Done!\n");
}
}
// Output:
// === Test 1: Successful Query ===
// Opening connection: localhost:3306
// Connection opened!
// Executing: SELECT * FROM users
// Query successful!
//
// [Finally Block]
// Closing connection...
// Connection closed!
// Done!
//
// === Test 2: Failed Query ===
// Opening connection: localhost:3306
// Connection opened!
// Executing: SELECT * ERROR FROM users
// Error: Query failed!
//
// [Finally Block]
// Closing connection...
// Connection closed!
// Done!
//
// === Test 3: Connection Failed ===
// Opening connection: invalid
// Error: Invalid connection string!
//
// [Finally Block]
// Done!

🔄 Finally with Return Statements

FinallyWithReturn.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public class FinallyWithReturn {
public static void main(String[] args) {
System.out.println("Result 1: " + testReturn1());
System.out.println("\nResult 2: " + testReturn2());
System.out.println("\nResult 3: " + testReturn3());
}
// Example 1: Return in try
public static int testReturn1() {
System.out.println("Test 1 started");
try {
System.out.println(" In try block");
return 10; // Method will return, but...
} finally {
System.out.println(" In finally block");
System.out.println(" Finally runs BEFORE return!");
}
// Note: Finally executes before the return value is sent back
}
// Example 2: Return in catch
public static int testReturn2() {
System.out.println("Test 2 started");
try {
System.out.println(" In try block");
int x = 10 / 0; // Exception!
return 10;
} catch (ArithmeticException e) {
System.out.println(" In catch block");
return 20;
} finally {
System.out.println(" In finally block");
System.out.println(" Finally runs even with return in catch!");
}
}
// Example 3: Return in finally (DON'T DO THIS!)
public static int testReturn3() {
System.out.println("Test 3 started");
try {
System.out.println(" In try block");
return 10;
} finally {
System.out.println(" In finally block");
return 99; // BAD PRACTICE: This overwrites try's return!
}
}
}
// Output:
// Test 1 started
// In try block
// In finally block
// Finally runs BEFORE return!
// Result 1: 10
//
// Test 2 started
// In try block
// In catch block
// In finally block
// Finally runs even with return in catch!
// Result 2: 20
//
// Test 3 started
// In try block
// In finally block
// Result 3: 99
// Important: Finally's return (99) overwrites try's return (10)!
// This is confusing and should be avoided!

⚡ Try-Finally Without Catch

TryFinally.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class TryFinally {
public static void main(String[] args) {
System.out.println("=== Test 1: No Exception ===");
test1();
System.out.println("\n=== Test 2: With Exception ===");
try {
test2();
} catch (Exception e) {
System.out.println("Main caught: " + e.getMessage());
}
}
// You can use try-finally without catch!
public static void test1() {
System.out.println("Method started");
try {
System.out.println("Doing some work...");
int result = 10 / 2;
System.out.println("Result: " + result);
} finally {
System.out.println("Cleanup in finally");
}
System.out.println("Method ended");
}
public static void test2() {
System.out.println("Method started");
try {
System.out.println("Doing some work...");
int result = 10 / 0; // Exception!
System.out.println("Result: " + result);
} finally {
// This runs even though exception isn't caught here
System.out.println("Cleanup in finally");
}
// This line never executes
System.out.println("Method ended");
}
}
// Output:
// === Test 1: No Exception ===
// Method started
// Doing some work...
// Result: 5
// Cleanup in finally
// Method ended
//
// === Test 2: With Exception ===
// Method started
// Doing some work...
// Cleanup in finally
// Main caught: / by zero
// Key point: Finally runs even when exception isn't caught locally!
// The exception propagates up after finally executes.

🎭 Nested Try-Catch-Finally

NestedTryCatch.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class NestedTryCatch {
public static void main(String[] args) {
System.out.println("Program started");
try {
System.out.println("\n1. Outer try");
try {
System.out.println(" 2. Inner try");
int result = 10 / 0; // Exception!
System.out.println(" This won't print");
} catch (ArithmeticException e) {
System.out.println(" 3. Inner catch: " + e.getMessage());
} finally {
System.out.println(" 4. Inner finally - always runs");
}
System.out.println("5. After inner try-catch-finally");
// Another operation
String text = null;
System.out.println(text.length()); // NullPointerException!
} catch (NullPointerException e) {
System.out.println("6. Outer catch: " + e.getClass().getSimpleName());
} finally {
System.out.println("7. Outer finally - always runs");
}
System.out.println("\n8. Program ended");
}
}
// Output:
// Program started
//
// 1. Outer try
// 2. Inner try
// 3. Inner catch: / by zero
// 4. Inner finally - always runs
// 5. After inner try-catch-finally
// 6. Outer catch: NullPointerException
// 7. Outer finally - always runs
//
// 8. Program ended
// Both finally blocks execute!
// Inner finally runs when inner try-catch completes
// Outer finally runs when outer try-catch completes

🆕 Modern Alternative: Try-With-Resources

TryWithResources.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class TryWithResources {
public static void main(String[] args) {
System.out.println("=== Old Way (with finally) ===");
readFileOldWay("data.txt");
System.out.println("\n=== New Way (try-with-resources) ===");
readFileNewWay("data.txt");
}
// Old way: Manual cleanup in finally
public static void readFileOldWay(String filename) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(filename));
String line = reader.readLine();
System.out.println("Read: " + line);
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
} finally {
// Manual cleanup - lots of code!
if (reader != null) {
try {
reader.close();
System.out.println("File closed in finally");
} catch (IOException e) {
System.out.println("Error closing: " + e.getMessage());
}
}
}
}
// New way: Automatic cleanup!
public static void readFileNewWay(String filename) {
// Resources declared here are automatically closed
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line = reader.readLine();
System.out.println("Read: " + line);
// No finally needed! Resource closes automatically
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
System.out.println("File auto-closed!");
}
}
// Try-with-resources benefits:
// 1. Shorter, cleaner code
// 2. Automatic resource cleanup
// 3. Proper exception handling
// 4. Works with any AutoCloseable resource
// 5. Multiple resources can be declared
// Syntax:
// try (Resource r1 = new Resource(); Resource r2 = new Resource()) {
// // use resources
// } // resources closed automatically

🔑 Key Concepts

Always Executes

Finally runs whether exception occurs or not

Perfect for cleanup code that must always run

Resource Cleanup

Close files, database connections, network sockets

finally { file.close(); }

Optional

You don't need finally if you don't need cleanup

try-catch is valid without finally

Execution Guarantee

Executes even if return statement in try/catch

Finally runs before method returns

Best Practices

  • Use finally for resource cleanup (closing files, connections)
  • Don't put return statements in finally block (confusing!)
  • Don't throw exceptions from finally (overwrites original exception)
  • Consider try-with-resources for automatic resource management
  • Keep finally blocks short and focused on cleanup
  • Avoid complex logic in finally blocks

💼 Interview Tips

  • Finally always executes, even with return statements in try/catch
  • Finally executes before method returns
  • If both catch and finally have return, finally's return wins
  • Finally executes even if exception is not caught
  • Understand try-with-resources as modern alternative
  • Know that finally doesn't execute if JVM crashes or System.exit()