java异常
什么是异常呢?
定义:当一个程序在运行过程中,出现了一些非正常执行流程的指令,那么就会产生一个事件对象,这个事件对象在java就简称为异常(Exception)。
An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program‘s instructions.
异常Handler:
当一个异常出现了,那么jvm就会去寻找一个Handler来处理这个异常。
下面树jvm调用过程以及Handler的调用过程,从图中可以看出,Handler过程是反序的。
异常的分类:
异常主要分为三类:
Error,代表这个异常非常致命,不需要被异常Handler捕获。
Checked Exception:受检异常,代表异常属于符合用户预期的异常,通常情况下,用户会采取相应的措施,尝试从异常中恢复,需要被异常Handler捕获。
Runtime Exception:运行时异常,通常是一个bug,一般用于表示该异常是用户没有预料到的,不需要被异常Handler捕获。
语法结构:
try语法结构:
try {
code
}
catch and finally blocks . . .
catch语法结构:
try {
} catch (ExceptionType name) {
} catch (ExceptionType name) {
}
finally语法结构:
try{
}catch(ExceptionType name){
}finally {
}
直接在方法中抛出并且捕获异常的结构:
public void method1() throws ExceptionType{
}
直接在方法中抛出异常
public void method1(){
if(index < 0){
throw new EmptyStackException();
}
}
异常的作用:
先看一个方法,使用的是伪代码...
readFile { open the file; determine its size; allocate that much memory; read the file into memory; close the file; }
在这个方法中,我们会执行如下几个步骤
1打开文件
2查看文件大小
3开辟内存空间
4读取文件内容到内存中
5关闭文件
但是如果这个方法出现如下问题
1文件不可打开
2文件大小不可预知
3内存空间不够了
4如果读取文件失败了
5关闭文件失败了
如果不适用异常来处理这些异常,那么代码会是怎样子呢?
errorCodeType readFile { initialize errorCode = 0; open the file; if (theFileIsOpen) { determine the length of the file; if (gotTheFileLength) { allocate that much memory; if (gotEnoughMemory) { read the file into memory; if (readFailed) { errorCode = -1; } } else { errorCode = -2; } } else { errorCode = -3; } close the file; if (theFileDidntClose && errorCode == 0) { errorCode = -4; } else { errorCode = errorCode and -4; } } else { errorCode = -5; } return errorCode; }
每次客户端调用这个方法,都需要判断返回的状态码,从而来决定下一步来做什么...比如:
int status = readFile(); switch(status){ case -1: do something... case -2: do someting... }
这种代码是会让你发疯的,特别是一段时间之后,你再回来看这些代码,你会发现可读性特别差,如果在readFile()中再添加一些新的状态码,那么客户端的代码需要跟着一起
改变,这会给维护带来毁灭性的的工作,并且很容易引入新的bug。
下面是使用异常之后的代码:
readFile { try { open the file; determine its size; allocate that much memory; read the file into memory; close the file; } catch (fileOpenFailed) { doSomething; } catch (sizeDeterminationFailed) { doSomething; } catch (memoryAllocationFailed) { doSomething; } catch (readFailed) { doSomething; } catch (fileCloseFailed) { doSomething; } }
通过异常,我们可以让代码的可读性更加完整,并且如果新增加异常,也不会改动客户端的代码。
我们再来看看另外一个列子
method1 { call method2; } method2 { call method3; } method3 { call readFile; }
这是一个方法调用栈,方法method1() call method2() call method()3 call readFile()
如果没用异常处理机制,那么每个方法都会被强制进行错误诊断,那可是相当麻烦的,如下代码:
method1 { errorCodeType error; error = call method2; if (error) doErrorProcessing; else proceed; } errorCodeType method2 { errorCodeType error; error = call method3; if (error) return error; else proceed; } errorCodeType method3 { errorCodeType error; error = call readFile; if (error) return error; else proceed; }
好吧,看完之后,你会被很多无关代码弄得心烦意乱了,各种乱...
下面我们使用异常来处理:
method1 { try { call method2; } catch (exception e) { doErrorProcessing; } } method2 throws exception { call method3; } method3 throws exception { call readFile; }
我们仅仅在只关心的方法中处理异常...瞬间世界美好了。
另外,异常可以帮助我们将一些错误进行分类处理。比如在java.io中,需要各种各种的IO错误,比如打开文件失败,访问文件失败,关闭输出流失败等,我们都可以将这些异常归结为IOException,从更加高的层次去看待问题。
自定义异常:
通常情况下,如果你在开发一个工具包,出现了异常,那么用户可以直接自定义异常。异常的自定义非常简单,通常类名就表示错误类别。如:IllegalArgumentException,IOException,NegativeIndexException,FileNotFoundException等...但是有一点需要注意的是,选择继承的异常类很重要。如果错误是不可预知的,属于bug的,可以继承RuntionException,要么继承Exception吧。