章
目
录
Java try、catch 和finally块有助于编写可能在运行时抛出异常的应用程序代码,并让我们有机会通过执行备用应用程序逻辑从异常中恢复或优雅地处理异常以向用户报告。它有助于防止难看的应用程序崩溃。
请注意,建议每次可以使用时都使用try-with-resources块。
1. 基础知识
在深入了解这个概念之前,让我们先了解一下try-catch块及其语法的基本理解。
1.1. 尝试
try块包含预期在正常条件下工作的应用程序代码。例如,读取文件、写入数据库或执行复杂的业务操作。
try 块是用try关键字编写的,后跟大括号。
try {
//可能有异常的代码
}
1.2. catch
可选的catch块位于try块之后,并且必须处理try块抛出的已检查异常以及任何可能的未检查异常。
try {
//code
}
catch(Exception e) {
//handle exception
}
应用程序可能会以 N 种不同的方式出错。这就是为什么我们可以将多个 catch 块与一个 try 块关联起来。在每个 catch 块中,我们可以以一种独特的方式处理一个或多个特定的异常。
当一个catch块处理异常时,下一个catch块不会被执行。控制权直接从执行的 catch 块转移到执行程序的其余部分,包括finally块。
try {
//code
}
catch(NullPointerException e) {
//handle exception
}
catch(NumberFormatException e) {
//handle exception
}
catch(Exception e) {
//handle exception
}
1.3. finally
可选的finally块使我们有机会在每次try-catch块完成时运行我们想要执行的代码——无论有错误还是没有错误。
即使我们未能在catch块中成功处理异常,finally块语句也能保证执行。
try {
//open file
//read file
}
catch(Exception e) {
//handle exception while reading the file
}
finally {
//close the file
}
1.4. 只有try块是强制的
请注意,只有try块是强制性的,而catch和finally块是可选的。通过try块,我们可以根据需要使用catch块或finally块。
下面给出了 Java 中的两种组合。两个版本均有效。
try {
}
catch(Exception e) {
}
try {
}
finally {
}
2.在Java中,异常是如何传递的?
在正常情况下,当运行时发生异常时,JVM会将错误信息包装在Throwable的子类型的实例中。这个异常对象类似于其他Java对象,具有字段和方法。
唯一的区别是JVM会检查它们的存在并将控制传递给可以处理此异常类型或其父类类型的catch块。
当应用程序中没有找到适用于异常的catch块时,未捕获的异常将由JVM级别的默认异常处理程序处理。它会向用户报告异常并终止应用程序。
3.使用try、catch和finally块的不同执行流程
让我们看一些示例,以了解在不同情况下执行的流程。
3.1. try、catch和finally块 – 没有发生异常
如果没有发生异常,那么JVM将只执行finally块,catch块将被跳过。
try
{
System.out.println("try block");
}
catch (Exception e)
{
System.out.println("catch block");
}
finally
{
System.out.println("finally block");
}
程序输出:
try block
finally block
3.2. try、catch和finally块 – 发生异常
如果在try块中发生异常,那么JVM将首先执行catch块,然后执行finally块。
try
{
System.out.println("try block");
throw new NullPointerException("Null occurred");
}
catch (Exception e)
{
System.out.println("catch block");
}
finally
{
System.out.println("finally block");
}
程序输出:
try block
catch block
finally block
3.3. try 和finally 块——异常未处理
如果任何提供的 catch 块都没有处理异常,则 JVM 默认异常处理程序会处理它。在这种情况下,将执行finally块,然后执行默认的异常处理机制。
try
{
System.out.println("try block");
throw new NullPointerException("Null occurred");
}
finally
{
System.out.println("finally block");
}
程序输出:
try block
finally block
Exception in thread "main"
java.lang.NullPointerException: Null occurred
at com.howtodoinjava.Main.main(Main.java:12)
3.4. try、catch 和finally 块——多个catch 块
如果有多个与 try 块关联的 catch 块,则异常将由序列中可处理异常类型或其父类型的第一个catch块处理。
例如,处理IOException 的catch 块也可以处理FileNotFoundException类型的异常,因为FileNotFoundException extends IOException
.
try
{
System.out.println("try block");
throw new NullPointerException("null occurred");
}
catch (NumberFormatException e)
{
System.out.println("catch block 1");
}
catch (NullPointerException e)
{
System.out.println("catch block 2");
}
catch (Exception e)
{
System.out.println("catch block 3");
}
finally
{
System.out.println("finally block");
}
程序输出:
try block
catch block 2
finally block
3.5. try、catch 和finally 块——catch块抛出异常
有时在catch块中处理另一个异常时可能会出现异常。又将如何处理呢?
如果catch块中出现异常,执行将转移到与相应 catch 块关联的finally块(如果有)。然后异常在方法调用堆栈中传播,以查找可以处理此异常的catch块。
如果找到这样的catch块,则处理异常,否则 JVM 默认异常处理程序将处理异常并终止应用程序。
try
{
System.out.println("try block");
throw new NullPointerException("NullPointerException occured");
}
catch (NullPointerException e)
{
System.out.println("catch block 1");
throw new NumberFormatException("NumberFormatException occurred");
}
catch (Exception e)
{
System.out.println("catch block 2");
}
finally
{
System.out.println("finally block");
}
程序输出:
try block
catch block 1
finally block
Exception in thread "main"
java.lang.NumberFormatException: NumberFormatException occurred
at com.howtodoinjava.Main.main(Main.java:18)
4. Java 7 try-with-resources
对于AutoCloseable资源(例如流),Java SE 7 引入了try-with-resources语句,这是在上述场景中处理异常的推荐方法。在这种方法中,我们不需要关闭流,JVM 会为我们做这件事。它消除了对finally块的需要。
在 try-with-resources 中,资源在小括号内的try块中打开,最后块完全消失。
try (BufferedReader br = new BufferedReader(new FileReader("C:/temp/test.txt")))
{
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null)
{
System.out.println(sCurrentLine);
}
}
catch (IOException e)
{
e.printStackTrace();
}