Java面试必知:异常
异常
异常的体系结构
异常类
Throwable类 — 可抛出的
- 是所有异常或者错误的顶层父类
- 构造方法: Throwable(); Throwable(String message);
- 常用方法
- getMessage()–获取异常的错误信息
- toString()–返回整体类型 + 异常的错误信息
- printStackTrace()–打印异常栈信息,包括异常类名,调用的方法名,文件名,出错行数
Error类
- 由于JVM或硬件引发的严重问题,无法通过程序代码捕获和处理,所有错误的类名都以Error结尾
VirtualMachineError—虚拟机错误
OutOfMemoryError—内存超出错误
*Error—栈溢出错误
Exception–异常类
- 需要程序捕获和处理
- 运行时异常
- ArithmeticException—算术异常
- ClassCastException—类型转换异常
- IndexOutOfBoundsException—下标越界异常
- NullPointerException—空指针异常
- 编译时异常
- ClassNotFoundException—类没找到异常(JDBC部分)
- InterruptedException—线程中断异常(线程部分)
- IOException:
- FileNotFoundException—文件没找到异常(IO部分)
- SocketException–网络通信异常(网络部分)
- SQLException—SQL异常(JDBC部分)
- 运行时异常可以不做处理,但编译时异常必须进行处理.
异常的产生与处理
异常的默认处理
- 程序一但出错,JVM就会创建一个相应的异常对象,如果没有处理语句,则会一直往上抛,直到main()方法,最终自动调用printStackTrace()方法打印异常栈的信息
- 每调用一个方法,就会把当前方法进入方法栈,所以调用printStackTrace方法打印的时候,打印顺序和执行顺序正好是相反的
try—catch异常处理
- 如果try块没有任何错误 则会跳过 catch块
- 如果try块出现错误,Jvm会创建相应的异常对象,在catch块匹配相应的Exception类.catch块执行完成后,跳出try-catch块,继续执行后续语句. 如果没有匹配到,则会向上抛出,直到main()方法,最终调用printStackTrace方法
- 异常捕获(catch)应该尽量细化,一个try可以匹配多个catch
- catch块的排列顺序应该是子类在上,父类在下
throw和throws
- throw关键字 用于手动抛出一个异常
- throws用于声明本方法体可能抛出的异常
- 如果一个方法的内部抛出一个运行时异常,则不强制要求进行处理
- 如果一个方法的内部抛出一个编译时异常,则需要进行try-catch或者throws操作.(如果使用throws操作,则调用方也必须进行处理)
- throw语句 后面的语句不会再执行
运行时异常和编译时异常的区别
- 运行时异常因为是指运行之后,因为错误的数据而导致的异常.因此在编译时,不强制性对此异常进行处理
ArithmeticException—算术异常
ClassCastException—类型转换异常
IndexOutOfBoundsException—下标越界异常
NullPointerException—空指针异常 - 编译时异常必须进行处理,要不编译不通过
ClassNotFoundException—类没找到异常
InterruptedException—中断异常
IOException—IO异常
SQLException—SQL异常(JDBC部分)
何时使用捕获异常,何时使用抛出异常
-
只抛不try
方法的功能本身没有问题,由于调用者传递的参数导致的错误,抛给调用者处理. -
只try不抛
- 在继承关系中,子类重写父类方法时,子类方法抛出的异常类型要小于或者等于父类方法抛出的异常类型,因此对于非父类异常及其子类,只能自行捕获并处理
- 如果抛出异常会影响用户交互,应该自行处理异常
-
实际开发中,两种方式可以结合使用,既在方法中捕获异常,以便记录日志信息,又将异常重新封装(一般把编译型异常转译运行时异常),再抛出给调用方去处理
finally块
- finally块中的语句无论是否发生异常都会执行
- finally不能单独存在,必须和try搭配使用
- finally语句任何情况下都会执行,及时是前面有return语句,也会在return前先执行finally程序块.(除非遇到System.exit(0)强制退出)
自定义异常
- 违反逻辑的错误,可以自己定义一个异常类
- 捕获了一个编译时异常后,可以将异常对象重新包装成一个运行时异常对象,再次抛出给调用者.这样调用方对该异常的处理方式就变得灵活,既能知道发生了异常,又可以选择不对异常进行处理
- 在分层的软件结构中,上层模块无需关心底层的异常细节,常见的做法是捕获原始异常,并将其转换为一个新的异常对象,再抛出给上层模块
异常处理的优化原则
- 异常是用来描述非正常情况,不要用来处理正常逻辑
- 养成良好的编码习惯,及时进行检查,避免出现运行时异常
- 避免庞大的try块
- 避免笼统的捕获异常或者笼统的抛出异常,尽量使异常具体化
- 不要在catch中忽略异常,应该进行及时的处理.如进行日志记录等
- 资源释放应该放在finally块中,保证无论是否抛出异常,都可以进行有效执行