Java异常机制分析
概念
异常是指程序在运行期间所发生的错误,如使用了空指针、栈溢出、非法参数等。在程序编写期间,编译器会自动检查代码是否符合规范,并尽可能地帮助程序员将其纠正。但即使是看似正确的代码,也可能会在运行期间抛出一个意想不到的异常。
Java为此提供了异常处理机制,即在程序运行期间,倘若抛出了异常,则可以以适当的方式进行捕获处理,使得程序能够正常的运作下去。
体系结构
在Java中所有的异常类都是从java.lang.Throwable
类集成的子类。
根类Throwable
下(仅)有两个重要的子类——Error
与Exception
。
Error
代表运行期间JVM(Java虚拟机)出现的异常,这种异常一般来说是无法处理的。Exception
代表运行期间程序本身的逻辑出现的异常,这种异常一般是程序本身可以处理的。
其中,Exception
可分为两类:运行时异常和检查异常。
- 检查异常(CheckedException),是指程序在执行某段代码时,是可以提前知道这段代码是存在潜在异常的,而且要求程序必须以某种方式来处理。若不处理这种异常情况时,编译器是不会通过编译的。
- 运行时异常(RuntimeException),也称为非检查异常,是指程序在运行期间可能会抛出异常,但不要求程序必须处理该异常。在编译期间,编译器也不会要求用户去处理它。
TRY-CATCH会不会性能消耗
当初的自己觉得如果在try-catch
块中大量使用循环的话,想当然的认为会消耗大量的性能。但是通过阅读多篇文章后,得出以下结论:
- 异常如果没发生,也就不会去查异常表,也就是说你写不写
try-catch
,也就是有没有这个异常表的问题,如果没有发生异常,写try-catch
对性能是木有消耗的,所以不会让程序跑得更慢。 try-catch
的范围大小其实就是异常表中两个值(开始地址和结束地址)的差异而已,也是不会影响性能的。
具体文章如下所示:
优化建议
优化建议这一部分是结合了Java异常处理和设计和异常处理的 15 个处理原则两文的精华,小弟只能做个低调的搬运工。
- 只在必要使用异常的地方才使用异常,不要用异常去控制程序的流程
即使在上述的说到异常机制不会怎么消耗性能,但这并不代表能够在程序中随处使用try-catch
。要在程序中谨慎地使用异常,倘若异常使用过多仍然会很大程度上影响程序的性能。如果在程序中能够用if
语句来进行逻辑判断,自然能更清楚地表明出当某个字段处于某个阶段时要进行的逻辑,也可以减少异常的使用,从而避免不必要的异常捕获和处理。
- 切忌使用空
catch
块
倘若程序在捕获了异常之后什么都不做,相当于你直接隐藏了这个异常,这可能会导致后面的程序逻辑出现不可控的执行结果,这是一种相当不负责任的行为。倘若有这种情况发生,不如改变程序本身的代码逻辑,使其变得更加健壮,并用日志的方式记录其异常的状态,方便日后的更新和维护。
- 检查异常与非检查异常的选择
当你决定要抛出一个自己新定义的异常,你就要决定以什么形式来处理这个异常。
当有些检查异常对开发人员来说是无法通过合理的手段处理的,例如SQLException
,这样就会导致在代码中经常出现的一种情况:逻辑代码很少几行,但是要进行异常捕获和异常处理的代码却有很多行,这会导致逻辑代码阅读起来晦涩难懂,使得代码难以维护。
在检查异常与非检查异常的选择上面,如果存在该异常情况的出现很普遍,需要特别提醒调用者注意处理的话,就是用检查异常,否则就使用非检查异常。
- 注意
catch
块的顺序
切忌将捕获父类异常的catch
块放置于捕获子类异常catch
块前,否则将永远无法到达程序理想的异常处理逻辑状态中。
1 | try { |
- 避免多次在日志信息中记录同一异常
很多情况下异常都是层层向上抛出,如果在每次向上抛出异常的时候,都记录到日志中,则会导致冗余的异常重复记录在日志中,不仅大量浪费空间,而且很难查找到异常的根源。
妥当的做法是只在异常最开始发生的地方进行日志信息记录。
- 在
finally
中释放资源
如果在程序中存在文件读取、网络操作以及数据库操作等,需要在finally
块中释放资源。这样不仅使得程序占用的资源更少,也会避免由于资源未及时释放而导致的异常情况。
- 不要在
finally
中使用return
语句
倘若在正常try
块中返回值,又或者是,在捕获异常后打算在catch
块中返回值的话,切忌在finally
块中再返回值,否则finally
的返回值将直接取代catch
块中的返回值。这不难想象,因为finally
块在try-catch
执行完后一定会执行的,所以finally
中的操作将会正常执行。
1 | try { |
- 当方法判断出错该返回时应该抛出异常,而不是返回一些错误值
因为错误值在程序逻辑中可能会出现难以理解的情况,并且错误值在描述异常的情况并不直观。在文件找不到的时候,应当抛出类似 FileNotFoundException 异常,而不是返回 -1 或者 -2 之类的错误值。
参考资料