在Java中,执行逻辑被意外的中断,程序跳出了正常运行的轨道,这就是异常。

异常机制的优点

异常是Java的一种语言特征,被用来处理程序运行失败的情况,是强制停止程序继续错误运行的一种手段。当异常发生,程序不知道如何处理时,会把异常抛出,程序会按照原路进行返回,直到异常被处理,从而也可认为异常是一种错误的恢复机制。

与其他语言(例如C)进行比较,看看在它们是如何进行异常处理的:

if (chdir("C:\\temp"))
printf("Unable to change to temp directory: %d\n", errno);
FILE *fp = fopen("C:\\temp\\foo");
if (fp == NULL)
printf("Unable to open foo: %d\n", errno);

看到了吗?方法的调用后总是需要通过返回值来判断程序是否正常,这种方式,会使得正常的逻辑和异常处理的逻辑混为一体,不仅代码的可读性极差,工作量大,危险性也高,如果程序员不认为他写的代码会发生错误,从而忽视判断,那么继续运行的程序结果将如何?答案是,无人知晓。。

与此对比,Java通过异常机制强制终止程序,并使用捕捉异常的机制使程序进行恢复,就是一个很大的进步。

异常的分类

Java中通过Throwable这个类来表示任何可以被当成异常而被抛出的类,有两种类型:Error被用来表示编译时和系统错误(编码时异常通常不需要处理),Exception表示是可以被抛出异常的基本类型,它又可以分为被检查异常和运行时异常两种。

被检查异常

这种异常被抛出的条件是需要在方法定义后面显式的声明throws关键字,不然编译器会报错Unhandled Exception,而调用方也需要显式try-catch处理的异常,否则编译器会报错Unhandled Exception。

static void f1() throws Exception {
throw new Exception();
}

运行时异常

这类异常都是从RuntimeException继承而来的,如果发生,会自动的被JVM抛出,不需要显式在方法后声明,调用者也不是必须要进行显式捕捉,这类异常叫运行时异常,也被称为不受检异常。

static void f1() {
throw new RuntimeException();
}

异常处理及使用

当异常对象被抛出,catch异常处理程序会按照代码书写的顺序匹配最近的异常声明,查找的时候并不需要抛出的异常完全匹配声明异常,基类是可以处理子类异常的。

异常机制能让我们编写代码的时候能够更专注于当前的业务逻辑,这样对于代码而言,主干路会更加清晰,异常处理程序则可以集中在某个角落,等待可能到来的异常。

到底该如何使用受检异常或者运行时异常?

过分的使用受检异常会使得API的调用很不方便,过多的catch语句会让掉用方背负很大的负担。

所以,有经验准则:当正确的使用API也会产生异常且异常捕捉后能够知道如何处理以恢复程序,这两个条件同时满足,可以使用受检异常,否则应该使用运行时异常。