Java的异常处理——概念
在java遇到问题时,不可避免的造成程序的无法进行,这种情况叫做异常,比如输入错误、文件不存在甚至是程序逻辑错误。而如果一个用户在运行程序期间由于程序错误无法再使用这个程序就十分糟糕。为了避免这类情况发生,至少应该做到以下几点:
- 向用户通告错误;
- 保存所有的工作结果;
- 允许用户以妥善的方式退出。
对于这样的处理方式,java称作异常处理。以上的处理方式具体到程序就是——
- 返回到一种安全的状态,能让用户执行一些其他的命令;或者
- 允许用户保存所有操作的结果,并以妥善的方式退出终止程序。
要做到这些并不容易,因为错误的种类很多,想要检测错误条件的代码通常要离达到这个目标相去甚远,更何况每种错误有着不一样的处理方式。所以异常处理的任务是将控制权从错误产生的地方转移至能够处理错误的地方,而为了能处理这些问题,必须要研究程序中可能出现的问题和错误。
Java的这些异常
将Java中常见的错误按照继承的关系展示就如下图所示:
以字典的方式全部罗列就是:
类别 | 常用异常类 |
---|---|
Error | AssertionError、OutOfMemoryError、StackOverflowError |
UncheckedException | AlreadyBoundException、ClassCastException、ConcurrentModificationException、IllegalArgumentException、IllegalStateException、IndexOutOfBoundsException、JSONException、NullPointerException、SecurityException、UnsupportedOperationException |
CheckedException | ClassNotFoundException、CloneNotSupportedException、FileAlreadyExistsException、FileNotFoundException、InterruptedException、IOException、SQLException、TimeoutException、UnknownHostException |
其中有的异常设计的不好,在此引用——
- ConcurrentModificationException:实现“快速失败”的机制,但实际上,“快速失败”机制本身仍然无法保证并发环境下安全性,参考源码|从源码分析非线程安全集合类的不安全迭代器。因此,虽然该异常很常见,不要去依赖它。
- JSONException:常见于json字符串解析失败的情况,但遮蔽了大量的失败细节,往往很难根据该异常作出处理。如果项目中大量使用json,建议使用第三方的json解析库,如gson等。
- UnsupportedOperationException:这是一种编码上的恶性妥协,经常在抽象类的成员方法中被用户主动抛出,表示该方法还未实现等,但由于是UncheckedException,运行期才能够发现,完全无益于编码期间的安全性。自己编码时尽量不要使用。
- SQLException:与JSONException原因相似,但其遮蔽的失败细节范围更广。同时,SQLException还是一个CheckedException,在不能解决问题的情况下,又使代码变的臃肿不堪。建议同。如果做Java Web开发,热门的ORM库都能解决上述问题。
然后就是几个常见且重要的异常。
常用异常类的使用场景
Error
Error通常描述了系统级的错误,并且程序猿无法主动处理——当然,系统级错误也有可能由代码间接导致。发生系统级错误的时候,系统环境已经不健康了,因此,Error不强制捕获或声明,也就是不强制处理,一般情况下只需要把异常信息记录下来(如果能记下当时的系统快照更好)。
OutOfMemoryError
当可用内存不足时,会由JVM抛出OutOfMemoryError。一般由三种原因导致:
- 堆设置过小,不满足正常的内存需求
- 代码中存在内存泄露,占用了大量内存而不能被回收
- 选择的GC算法与某些极端的应用场景不匹配,内存碎片过多,没有足够大的连续空间分配给对象
JVM抛出OutOfMemoryError前,会尝试进行一次Full GC,如果GC后可用内存还是不足,才会抛出OutOfMemoryError。因此,这时程序猿必然无法主动处理这一问题,只能等程序崩溃后再去查证原因。
UncheckedException(同RuntimeException)
UncheckedException描述运行期发生,通常由于代码问题直接引起的程序相关的错误,并且程序猿无法主动处理。UncheckedException也不强制捕获或声明,也就是不强制处理,一般情况下记下日志即可。
NullPointerException
NullPointerException是最常见的UncheckedException。如果在一个空指针上引用方法或变量等,则运行期会抛出NullPointerException。空指针让程序变的不可控:如果任由空指针在程序运行期随意传递、使用,我们将无法确定程序的行为,也无法确定捕获NullPointerException时程序所处的状态。
解决这一问题的方法很简单:
- 尽早检查并主动抛出异常
- 单独、提前处理边界条件
- 尽量不使用null表示状态,特别是在集合中
前两条原则通用于大部分UncheckedException,可参考String#toLowerCase()的例子。第三条原则需要在代码的健壮与简洁之间做出权衡,有限保证简洁清晰,需要健壮再去健壮。
IllegalArgumentException
参数错误,这个常见于各类方法的调用是传参错误,这个修改参数或者转换类型就可以解决。同样还有NumberFormatException。
CheckedException(IOException等)
CheckedException是外部环境引发的不太严重的问题,需要程序猿尽快处理。CheckedException强制捕获或声明,程序猿必须处理。记录日志,包装后再次抛出,在方法签名中声明,是三种最常见的做法。
IOException
FileAlreadyExistsException、FileNotFoundException、UnknownHostException等,都是IOException的子类。这些有相似的异常大概来说都是找东西但找不到,只能抛出异常来解决,这一类只能程序猿注意下了,毕竟发生这些情况的原因很多。
总结
Java中异常种类很多,不够还可以自己自定义,以上是我从网上搜集的,可能有很多有问题的地方,但多少能帮助理解。