杰瑞科技汇

try finally 在 Java 中一定会执行吗?

Of course! Let's dive deep into the try-finally block in Java. It's a fundamental construct for resource management and exception handling.

try finally 在 Java 中一定会执行吗?-图1
(图片来源网络,侵删)

The Core Idea: What is try-finally?

The try-finally block is used in Java to define a block of code that you always want to execute, regardless of whether an exception was thrown or not within the try block.

The basic syntax is:

try {
    // Code that might throw an exception
} finally {
    // Code that will ALWAYS run, no matter what
}

Why Use try-finally? The Primary Use Case

The most common and important use case for try-finally is resource cleanup. When you open a resource like a file, a network connection, or a database connection, you must close it to free up system resources.

A finally block is the perfect place to put this cleanup code because it's guaranteed to run. This ensures that your resources are not leaked, even if an error occurs while you are using them.

try finally 在 Java 中一定会执行吗?-图2
(图片来源网络,侵删)

Classic Example: Closing a File

Imagine you're reading from a file. What happens if the file doesn't exist or an error occurs while reading? Without finally, your fileReader.close() line might never be reached, leaving the file handle open.

The Problematic Code (without finally):

import java.io.FileReader;
import java.io.IOException;
public class BadResourceHandling {
    public static void main(String[] args) {
        FileReader fileReader = null; // Declare outside the try block
        try {
            fileReader = new FileReader("my_file.txt");
            // Let's assume an error happens here during reading...
            char c = (char) fileReader.read(); // Potential IOException
            System.out.println("Read character: " + c);
        } catch (IOException e) {
            System.err.println("An error occurred while reading the file!");
            // If an exception happens here, the program jumps to the catch block
            // and the fileReader.close() is NEVER executed.
        }
        // This line might be skipped if an exception occurred!
        if (fileReader != null) {
            try {
                fileReader.close();
            } catch (IOException e) {
                System.err.println("Error closing the file.");
            }
        }
    }
}

The Correct Code (with try-finally):

This is much cleaner and safer. The finally block guarantees the file is closed.

try finally 在 Java 中一定会执行吗?-图3
(图片来源网络,侵删)
import java.io.FileReader;
import java.io.IOException;
public class GoodResourceHandling {
    public static void main(String[] args) {
        FileReader fileReader = null;
        try {
            fileReader = new FileReader("my_file.txt");
            char c = (char) fileReader.read();
            System.out.println("Read character: " + c);
        } catch (IOException e) {
            System.err.println("An error occurred while reading the file!");
        } finally {
            // This block is GUARANTEED to run, whether an exception occurred or not.
            System.out.println("Executing finally block...");
            if (fileReader != null) {
                try {
                    fileReader.close(); // Clean up the resource
                    System.out.println("File closed successfully.");
                } catch (IOException e) {
                    System.err.println("Error closing the file.");
                }
            }
        }
        System.out.println("Program finished.");
    }
}

How try-finally Behaves

The behavior of try-finally depends on what happens inside the try block.

Scenario 1: No Exception Occurs

  1. Code inside the try block executes from top to bottom.
  2. After the try block finishes, the code inside the finally block is executed.
  3. Execution continues after the try-finally block.
try {
    System.out.println("Inside try block.");
} finally {
    System.out.println("Inside finally block.");
}
System.out.println("After try-finally block.");

Output:

Inside try block.
Inside finally block.
After try-finally block.

Scenario 2: An Exception Occurs

  1. Code inside the try block executes until an exception is thrown.
  2. The JVM looks for a catch block that can handle the exception. If there is no matching catch block (like in a try-finally), the exception is "propagated" up the call stack.
  3. Crucially, BEFORE the exception is propagated, the code inside the finally block is executed.
  4. After the finally block completes, the exception continues to propagate.
public class ExceptionExample {
    public static void main(String[] args) {
        try {
            System.out.println("Inside try block.");
            int result = 10 / 0; // ArithmeticException is thrown here
            System.out.println("This line will never be reached.");
        } finally {
            System.out.println("Inside finally block. (Runs before exception propagates)");
        }
        System.out.println("This line will also never be reached.");
    }
}

Output:

Inside try block.
Inside finally block. (Runs before exception propagates)
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at ExceptionExample.main(ExceptionExample.java:8)

Notice that the finally block ran, but the lines after the try-finally block did not, because the exception was still unhandled.


The Modern Alternative: try-with-resources (Java 7+)

While try-finally works perfectly, Java 7 introduced a more concise and often safer way to handle resources called the try-with-resources statement. It automatically closes any resource that implements the AutoCloseable interface (which includes FileReader, Connection, Socket, etc.).

try-with-resources Example:

import java.io.FileReader;
import java.io.IOException;
public class TryWithResourcesExample {
    public static void main(String[] args) {
        // The resource is declared inside the try parentheses
        try (FileReader fileReader = new FileReader("my_file.txt")) {
            char c = (char) fileReader.read();
            System.out.println("Read character: " + c);
            // No need for a finally block to close the fileReader!
            // It will be closed automatically.
        } catch (IOException e) {
            System.err.println("An error occurred.");
        }
        System.out.println("Program finished. Resource is already closed.");
    }
}

Why is try-with-resources often better?

  1. Conciseness: Less boilerplate code. No need to write a finally block.
  2. Safety: It guarantees the resource is closed, even if an exception occurs. It also handles exceptions that can occur during the close() operation itself, which can be tricky with try-finally.
  3. Clarity: The resource management is tied directly to the try block where it's used.

When to use try-finally vs. try-with-resources?

  • Use try-with-resources for all standard resources that implement AutoCloseable. This should be your default choice in modern Java (7+).
  • Use try-finally when:
    • You are working with legacy code on an older Java version (pre-Java 7).
    • You need to perform cleanup that is not related to a resource that implements AutoCloseable. For example, logging a message, setting a flag, or performing other non-resource-related actions.

The return Statement in try-finally

This is a classic interview question and a point of confusion. If a return statement is inside a try block, does the finally block still run?

Yes, it absolutely does. The finally block has higher priority.

  1. When the JVM encounters a return statement in the try block, it does not immediately return.
  2. It first executes the entire finally block.
  3. Only after the finally block is complete does the method actually return.
public class ReturnFinallyExample {
    public static void main(String[] args) {
        System.out.println("The returned value is: " getValue());
    }
    public static int getValue() {
        try {
            System.out.println("Inside try block.");
            return 10; // The return value is calculated, but not returned yet
        } finally {
            System.out.println("Inside finally block.");
            // This runs BEFORE the method actually returns
        }
        // This line is unreachable
    }
}

Output:

Inside try block.
Inside finally block.
The returned value is: 10

What if you have a return in the finally block too? The finally block's return will override the try block's return.

public class OverrideReturnExample {
    public static void main(String[] args) {
        System.out.println("The returned value is: " getValue());
    }
    public static int getValue() {
        try {
            System.out.println("Inside try block.");
            return 10;
        } finally {
            System.out.println("Inside finally block.");
            return 20; // This return wins!
        }
    }
}

Output:

Inside try block.
Inside finally block.
The returned value is: 20

This behavior can be surprising and is generally considered bad practice because it can hide the original return value and make code harder to understand.

Summary Table

Feature try-finally try-with-resources
Purpose Guarantee code execution (for cleanup). Automatically manage resources that implement AutoCloseable.
Syntax try { ... } finally { ... } try (Resource r = ...) { ... }
Resource Closing Manual, inside the finally block. Automatic, at the end of the try block.
Java Version Since Java 1.0 Since Java 7
Best For General-purpose cleanup, legacy code. Files, streams, connections, sockets, etc.
分享:
扫描分享到社交APP
上一篇
下一篇