在Java中,finally
关键字用于创建一个代码块,它跟在一个try
块之后,可选地跟在一个或多个catch
块之后。无论try
块内发生什么情况(是否发生异常),finally
块中的代码几乎总是会被执行。finally
块通常用于清理资源,比如关闭文件、释放内存等,以确保这些代码无论正常逻辑还是异常处理都能得到执行。
这里有finally
的一些关键点:
- 正常执行:如果
try
块成功完成,没有异常发生,那么finally
块将在try
块之后执行。 - 异常处理:如果
try
块中发生异常,并且相应的catch
块匹配了这个异常并处理了它,那么finally
块将在catch
块之后执行。 - 无匹配的异常:即使
try
块中的异常没有被任何catch
块捕获(即没有匹配的catch
块),finally
块仍然会执行。 - 未处理的异常:如果
try
块或catch
块中抛出了一个未被捕获的异常,finally
块会在异常传播到更高层之前执行。 try
/catch
块中的return
语句:即使try
或catch
块中有return
语句,finally
块也会在方法返回之前执行。但是,如果finally
块中也有return
语句,它将会覆盖try
或catch
块中的返回值。try
块中的System.exit()
:如果try
或catch
块调用System.exit()
,那么JVM将会立即终止,finally
块不会执行。finally
块中的异常:如果finally
块中发生异常,且try
或catch
块中也有异常发生,那么finally
块中的异常将会“覆盖”之前的异常,导致之前的异常丢失。
下面是一个简单的例子,演示finally
块的基本用法:
public class FinallyDemo {
public static void main(String[] args) {
try {
int data = 25 / 5;
System.out.println(data);
} catch (ArithmeticException e) {
System.out.println(e);
} finally {
System.out.println("finally block is always executed");
}
System.out.println("Rest of the code...");
}
}
在这个例子中,finally
块将在try
块成功执行之后执行。即使没有异常被抛出,finally
块中的语句"finally block is always executed"
也会被打印出来。
如果你将25 / 5
替换为25 / 0
,将会发生ArithmeticException
,catch
块将会捕获并处理它,但是之后finally
块仍然会执行。
finally
块是确保资源被适当清理的重要机制,比如关闭文件流或数据库连接,即使在异常情况下也可以保证这些操作被执行。
几个不同情景中使用
finally`语句的Java代码示例:
示例 1: 确保关闭资源
import java.io.*;
public class FinallyExample {
public static void main(String[] args) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("input.txt"));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
在这个示例中,无论是否发生IOException
,finally
块都保证了BufferedReader
资源在使用后被关闭。
示例 2: try
/catch
/finally
结合return
public class FinallyReturnExample {
public static int myMethod() {
try {
// This will cause a divide by zero exception
int result = 25 / 0;
return result;
} catch (ArithmeticException e) {
System.out.println("ArithmeticException caught");
return -1;
} finally {
System.out.println("finally block executed");
// Return in a finally block will override any previous return
// But it's a bad practice to do so.
// return 0;
}
}
public static void main(String[] args) {
int value = myMethod();
System.out.println("Returned value: " + value);
}
}
在这个例子中,尽管catch
块捕获了异常并返回了-1
,finally
块依然会被执行。如果取消注释finally
块中的return 0;
,那么这个值将会覆盖catch
块中的返回值。
示例 3: finally
块中抛出异常
public class FinallyExceptionExample {
public static void myMethod() {
try {
throw new Exception("An error occurred");
} catch (Exception e) {
System.out.println("Error caught: " + e.getMessage());
throw e; // Re-throwing the exception
} finally {
System.out.println("finally block executed");
// Throwing an exception here would cause the previous thrown exception to be lost
// throw new RuntimeException("Exception from finally");
}
}
public static void main(String[] args) {
try {
myMethod();
} catch (Exception e) {
System.out.println("Caught in main: " + e.getMessage());
}
}
}
在这个示例中,finally
块在异常被catch
块捕获并处理之后执行。如果取消注释finally
块中的throw new RuntimeException("Exception from finally");
,这个新抛出的异常将会覆盖之前由try
块抛出的异常。
示例 4: 在finally
块中释放锁
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FinallyLockExample {
private static final Lock lock = new ReentrantLock();
public static void main(String[] args) {
lock.lock();
try {
// Critical section protected by the lock
System.out.println("Inside the critical section");
} finally {
lock.unlock(); // Ensure the lock is released regardless of what happens in the try block
}
}
}
在这个示例中,finally
块确保了无论在临界区代码执行期间发生什么情况,锁lock
最终都会被释放。