Java try-catch 块

2025 年 6 月 16 日 | 阅读 6 分钟

Java try 块用于包含可能抛出异常的代码。它必须在方法内使用。

如果在 try 块中的某个语句发生异常,则块中的其余代码将不会执行。因此,不建议在 try 块中保留不会引发异常的代码。

Java catch 块

Java catch 块用于通过在参数中声明异常类型来处理异常。声明的异常必须是父类异常(即 Exception)或生成的异常类型。但是,声明生成的异常类型是一种好方法。

catch 块只能在 try 块之后使用。您可以在单个 try 块中使用多个 catch 块。

Java try 块后必须跟一个 catch 块或 finally 块。

try-catch 块的语法

try-finally 块的语法

Java try-catch 块的内部工作原理

Java try-catch block

JVM 首先检查异常是否已处理。如果异常未处理,JVM 会提供一个默认的异常处理程序,该处理程序执行以下任务:

  • 打印异常描述。
  • 打印堆栈跟踪(异常发生的方法的层次结构)。
  • 导致程序终止。

但是,如果程序员处理了异常,应用程序的正常流程将得以维持,即其余代码将被执行。

try-catch 块的工作原理

  • Java 虚拟机开始执行 try 块中包含的代码。
  • 如果发生异常,JVM 将开始查找匹配的 catch 块,并跳过 try 块中其余的代码。
  • 如果找到匹配的 catch 块,则执行 catch 块中的代码。
  • 如果存在 finally 块,则在 catch 块之后将控制权转移到 finally 块。
  • 如果没有匹配的 catch 块,则通知 JVM 中的默认异常处理程序。
  • try-catch 块之后的 finally 块将被执行。无论是否发生异常。

没有异常处理的问题

让我们尝试理解如果不使用 try-catch 块来处理异常会发生什么问题。

示例:抛出 Arithmetic Exception(除以零)

输出

Exception in thread "main" java.lang.ArithmeticException: / by zero

如上例所示,其余代码未执行(在这种情况下,不会打印其余的代码语句)。

异常之后可能还有 100 行代码。如果未处理异常,则异常下方的所有代码都将不执行。

处理异常

让我们看看通过使用 Java try-catch 块解决上述问题的方案。

示例:处理 Arithmetic Exception(除以零)

示例

编译并运行

输出

java.lang.ArithmeticException: / by zero
rest of the code

如上程序所示,其余代码已被执行,即其余代码语句已打印在控制台上。

Java try-catch 块的优点

优雅的错误处理: 借助 try-catch 块,我们的软件可以处理异常而不会崩溃。可以仔细识别和处理某些异常。

程序连续性: 即使发生异常,此功能也能使程序继续运行。软件可以处理异常并继续运行,而不是突然终止。

捕获特定异常: 为了提高代码的弹性,您可以捕获多种异常类型(例如 IOException 和 SQLException)并以不同的方式处理它们。

堆栈跟踪日志记录: 当发生异常时,Java 的异常处理机制会自动生成堆栈跟踪,这有助于调试和定位错误的根源。

Finally 块: 无论是否发生异常,finally 块都确保关键的清理操作(例如终止资源(如文件或数据库连接))始终被执行。

Java try-catch 块的缺点

性能开销: 异常处理会带来性能开销。由于创建和处理异常可能需要大量资源,因此 try-catch 块可能导致应用程序滞后,尤其是在频繁抛出异常的情况下。

过度使用异常处理: 过度依赖 try-catch 块的代码可能会变得混乱且难以阅读,尤其是在异常处理不当或过于笼统的情况下。这可能导致忽略异常的根本原因。

捕获的异常过多: 如果捕获通用异常(如 Exception 或 Throwable),则可能会捕获不应在代码该部分处理的异常。这可能会隐藏代码中的实际问题。

复杂性: 考虑不周的异常处理逻辑可能导致代码复杂且具有层次结构。这可能使长期代码维护和理解程序流程变得更加困难。

Bug 隐藏: 通过捕获指向更严重问题的异常,try-catch 块有时会隐藏代码中的问题。如果异常处理不当或未记录,实际问题可能会被忽视。

状态不一致: 如果异常未得到妥善处理,它们可能导致程序出现不稳定,尤其是在未妥善清理资源或异常发生前状态未正确回滚的情况下。

Java try catch 块选择题

1. 关于 Java 中的 catch 块,以下哪项说法是正确的?

  1. 它后面必须跟一个 finally 块。
  2. 它可以在一个块中捕获多种类型的异常。
  3. 它必须指定它可以处理的异常类型。
  4. 它只能捕获未检查的异常。
 

答案:C

解释: Java 中的 catch 块必须指定它可以处理的异常类型。它允许该块处理特定的异常,而其他异常可以由不同的 catch 块捕获或传播到调用堆栈。


2. 如果在 try 块中抛出了异常但未找到匹配的 catch 块,会发生什么?

  1. 程序立即终止。
  2. 异常由默认处理程序捕获。
  3. 异常将被传播到调用堆栈。
  4. finally 块将被跳过。
 

答案:C

解释: 如果未找到匹配的 catch 块,则异常将被传播到调用堆栈中最近的匹配 catch 块。如果没有找到,默认的异常处理程序将终止程序。


3. 在哪种情况下 finally 块不会执行?

  1. 当抛出异常但未捕获时。
  2. 当在 try 块中调用 System.exit() 时。
  3. 当异常被 catch 块捕获时。
  4. 当 try 块正常完成时。
 

答案:B

解释: 如果 try 块调用 System.exit() 来终止 JVM,finally 块将不会执行。在所有其他情况下,finally 块将执行。


4. 关于嵌套的 try-catch 块,以下哪个陈述是正确的?

  1. 只有最内层的 catch 块可以处理异常。
  2. 异常可以被任何级别的任何匹配的 catch 块捕获。
  3. Java 中不允许嵌套的 try-catch 块。
  4. try 块不能嵌套在另一个 try 块中。
 

答案:B

解释: 在嵌套的 try-catch 块中,异常可以被任何级别的任何匹配的 catch 块捕获,从最内层的 catch 块到最外层的 catch 块。


5. 考虑以下代码

关于 catch 块的顺序,哪个陈述是正确的?

  1. catch 块可以按任何顺序排列。
  2. Exception 的 catch 块应放在 IOException 之前。
  3. IOException 的 catch 块应放在 Exception 之前。
  4. catch 块后面必须跟一个 finally 块。
 

答案:C

解释: IOException 的 catch 块必须放在 Exception 的 catch 块之前,因为 IOException 是 Exception 的子类。将更通用的 catch 块放在前面会使特定的 catch 块无法访问,并导致编译错误。