面试题答案
一键面试Java异常处理机制与异常类层次结构的协同工作
-
异常类层次结构
- 在Java中,所有异常类都继承自
Throwable
类。Throwable
类有两个主要子类:Error
和Exception
。 Error
通常表示系统级错误,如OutOfMemoryError
、StackOverflowError
等,这类错误一般是由Java虚拟机(JVM)抛出,应用程序通常不应该捕获和处理它们,因为在大多数情况下,应用程序无法对这类错误做出有效的恢复操作。Exception
类用于表示可以被应用程序捕获和处理的异常。它又分为Checked Exception
(受检异常)和Unchecked Exception
(非受检异常,运行时异常)。Checked Exception
要求在方法声明中使用throws
关键字声明抛出,或者在方法内部使用try - catch
块捕获处理,例如IOException
、SQLException
等。Unchecked Exception
(运行时异常)包括RuntimeException
及其子类,如NullPointerException
、ArrayIndexOutOfBoundsException
等,这类异常不需要在方法声明中声明抛出,应用程序可以选择捕获处理,也可以不处理(由JVM默认处理)。
- 在Java中,所有异常类都继承自
-
try - catch - finally机制
- try块:它包含可能会抛出异常的代码。当try块中的代码抛出异常时,程序会立即停止执行try块中剩余的代码,并跳转到与之匹配的catch块。
- catch块:用于捕获并处理特定类型的异常。在一个try块后面可以有多个catch块,用于捕获不同类型的异常。当异常被抛出时,Java会按照catch块的顺序依次检查每个catch块的异常类型是否与抛出的异常类型匹配。
- finally块:无论try块中是否抛出异常,也无论catch块是否捕获到异常并处理,finally块中的代码都会在try - catch块结束后执行(除非JVM在try - catch块执行期间崩溃)。它通常用于释放资源,如关闭文件、数据库连接等。
-
捕获异常时基于异常类层次结构决定捕获顺序及原因
- 捕获顺序:在编写catch块时,应该先捕获子类异常,再捕获父类异常。例如,如果有一个
IOException
(Exception
的子类)和一个Exception
的catch块,应该先写catch(IOException e)
,再写catch(Exception e)
。 - 原因:如果先捕获父类异常,那么子类异常也会被父类异常的catch块捕获,导致子类异常的特定处理逻辑无法执行。例如,如果先写
catch(Exception e)
,那么IOException
、SQLException
等Exception
的子类异常都会被这个catch块捕获,无法针对IOException
等子类异常进行特殊处理。按照从子类到父类的顺序捕获异常,可以确保每个异常类型都能得到合适的处理,并且遵循Java异常处理机制与异常类层次结构的设计原则。
示例代码如下:
public class ExceptionHandlingExample { public static void main(String[] args) { try { // 可能抛出异常的代码 int result = 10 / 0; } catch (ArithmeticException e) { // 捕获ArithmeticException异常 System.out.println("捕获到算术异常: " + e.getMessage()); } catch (Exception e) { // 捕获其他类型的异常 System.out.println("捕获到其他异常: " + e.getMessage()); } finally { System.out.println("finally块总是会执行"); } } }
在这个示例中,先捕获了
ArithmeticException
(RuntimeException
的子类),如果将catch(Exception e)
放在catch(ArithmeticException e)
之前,ArithmeticException
也会被catch(Exception e)
捕获,就无法实现针对ArithmeticException
的特定处理。 - 捕获顺序:在编写catch块时,应该先捕获子类异常,再捕获父类异常。例如,如果有一个