Java Finally块–异常处理
当代码中引发异常时,该方法的正常执行流程将中断,这可能导致打开的资源永不关闭。在这种情况下,我们确实需要一种清理机制,Java的最终阻止对清理机制有帮助。
例如,假设我们使用一种方法打开文件并开始使用输入流读取文件。在读取流时,将引发异常,并且永远不会执行关闭流的代码。这意味着流仍在使用资源,因为它从未关闭过。
通过使用finally块并将代码关闭在该finally块中,可以确保始终执行关闭流的代码。
Finally块
Java异常处理中的finally块可以立即跟随try块,使其成为try-finally块,或者我们可以拥有完整的try-catch-finally块。在try块之后必须是catch或者最后,当然我们也可以将两者都变成完整的try-catch-finally块。
无论是否在try块中引发异常,Java中的final块始终执行。如果try块内没有抛出异常,则try块存在时将执行finally块。
如果在try块中引发了异常,并且有一个catch块与所引发的异常的异常类型相匹配,则catch块首先执行,然后是finally块。万一catch块无法处理引发的异常,则在方法返回之前,仍然会执行block。
Java Finally代码块示例
让我们尝试通过示例Java程序查看这些场景
当catch块在那里并处理引发的异常时
public class ExceptionDemo {
public static void main(String[] args) {
ExceptionDemo ed = new ExceptionDemo();
double result = ed.division(7, 0);
System.out.println("result is - " + result);
}
private double division(int num1, int num2){
double result;
try{
result = num1/num2;
}catch(ArithmeticException exp){
System.out.println("Exception occurred while dividing" + exp.getMessage());
// assigining zero to result
result = 0;
}finally{
System.out.println("in finally block");
}
return result;
}
}
输出:
Exception occurred while dividing/ by zero in finally block result is - 0.0
当catch块存在但不处理引发的异常时
public class ExceptionDemo {
public static void main(String[] args) {
ExceptionDemo ed = new ExceptionDemo();
double result = ed.division(7, 0);
System.out.println("result is - " + result);
}
private double division(int num1, int num2){
double result;
try{
result = num1/num2;
}catch(NullPointerException exp){
System.out.println("Exception occurred while dividing" + exp.getMessage());
// assigining zero to result
result = 0;
}finally{
System.out.println("in finally block");
}
return result;
}
}
在catch块中,异常类型更改为NullPointerException,其中抛出的异常是ArithmeticException。在这种情况下,finally块仍将执行,然后将异常传播以由默认处理程序处理。
输出:
in finally block Exception in thread "main" java.lang.ArithmeticException: / by zero at com.theitroad.ExceptionDemo.division(ExceptionDemo.java:14) at com.theitroad.ExceptionDemo.main(ExceptionDemo.java:7)
如果在finally块中抛出异常会发生什么情况
如果try块中包含的代码引发异常,而finally块也引发异常,则finally子句引发的异常将掩盖try块中引发的异常。
让我们看一个例子来澄清它。假设我们具有读取文件的代码,并且传递的文件在给定路径中不存在。在这种情况下,将从try块引发FileNotFoundException。我们还有一个finally块,其中具有关闭BufferedReader对象的代码,但在这种情况下为null,因此finally块也将引发NullPointerException。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
public class FinallyDemo {
public static void main(String[] args){
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(
new FileInputStream(
new File("D:\test1.txt"))));
//br = null;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
System.out.println("In finally block");
try {
br.close();
} catch (NullPointerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
输出:
java.io.FileNotFoundException: D:\test1.txt (The system cannot find the file specified) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(Unknown Source) at java.io.FileInputStream.(Unknown Source) at com.theitroad.FinallyDemo.main(FinallyDemo.java:16) In finally block java.lang.NullPointerException at com.theitroad.FinallyDemo.main(FinallyDemo.java:25)
因此,我们应该避免在finally子句中引发异常。在上面的代码中,我们可以通过if条件检查是否为null至少避免NullPointerException。
if(br != null){
try {
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Java带return语句的finally块
即使try块中有return语句,并且try块中没有抛出异常,finally块仍将在方法返回之前执行。
public class FinallyDemo {
public static void main(String[] args) {
FinallyDemo fd = new FinallyDemo();
double result = fd.division(8, 4);
System.out.println("result is - " + result);
}
private double division(int num1, int num2){
double result;
try{
System.out.println("In try block");
return num1/num2;
}finally{
System.out.println("in finally block");
}
}
}
输出:
In try block in finally block result is – 2.0
如果在finally子句中也有return语句,则try语句返回的值将替换为finally块返回的值。此外,它还将抑制从try块引发的任何异常。这就是为什么在finally块中不应有任何return语句的原因。将finally块用于清理代码。
返回finally块示例
如果我们使用上面使用的示例代码并将return语句放置在finally块中,则将返回该值。另请注意,有尝试将其除以零,但该异常被抑制了。
public class FinallyDemo {
public static void main(String[] args) {
FinallyDemo fd = new FinallyDemo();
double result = fd.division(8, 0);
System.out.println("result is - " + result);
}
private double division(int num1, int num2){
double result;
try{
System.out.println("In try block");
return num1/num2;
}finally{
System.out.println("in finally block");
return 6;
}
}
}
输出:
In try block in finally block result is – 6.0
如果在finally块中注释return语句,然后运行程序,则可以看到异常。
Exception in thread "main" In try block in finally block java.lang.ArithmeticException: / by zero at com.theitroad.FinallyDemo.division(FinallyDemo.java:17) at com.theitroad.FinallyDemo.main(FinallyDemo.java:9)
什么时候Java Finally块不执行
虽然无论是否在try块中引发任何异常,finally块将始终执行。但是,在某些情况下,Java中的finally块没有执行。
如果在执行try或者catch代码的同时退出JVM(System.exit()或者JVM崩溃),则finally块可能不会执行。同样,如果执行try或者catch代码的线程被中断或者杀死,即使整个应用程序继续运行,finally块也可能不会执行。
重要事项
最后,Java中的代码块用于清理代码。我们应该将代码放在finally块中以关闭打开的资源(输入流,输出流,打开的DB连接)。
虽然finally块是可选的,但try块必须紧随catch或者finally块之后。我们也可以使用完整的try-catch-finally块。
无论try块是否无异常退出或者由于异常而退出,总是执行finally块。
只有当JVM退出或者执行try或者catch代码的线程被中断或者杀死时,finally块才不会执行。
如果finally块引发异常,则该异常将掩盖try块中引发的异常。
如果在finally块中有一个return语句,则返回值。
在finally块中包含return语句可能会抑制引发的异常,因此在finally块中不应存在return语句。

