异常,也有一套自己的体系,尤其是java的一大特征是封装,所以对应的,如果封装的方法中抛出的异常与它执行的任务没什么明显的关系,则很容易令人不知所措,给人以驴唇不对马嘴,尤其是方法是由底层抽象方法抛出的异常,更容易发生这种情况,不但编码规范错误,更可能污染高层的api,这样就可能破坏客户端的架构,为了避免这个问题,更高层的实现应该捕获底层的异常,同时向上抛出可以让更高层抽象解释的异常,这种做法叫做异常转译,异常体系架构就是以此为基础产生的。
单个的异常
try {
//use low-levelabstraction to do our bidding
} catch (LowerLevelException e) {
throw new HigherLevelException();
}
来自AbstractSequentialList类,抽象类,里面有get()方法,它是属于基类的方法,需要子类去实现,也可以说是底层方法,需要上层去实现对应的方法功能,它本身是实现了List<E>接口,按照List中get()方法的规范,异常是必须转译的。
public E get(int index) {
try {
return listIterator(index).next();
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
get()方法中调用了迭代器的listIterator(index).next() 方法,我们就要预防对应的错误,此时listIterator(int index)方法,注释说的很明白,@throws IndexOutOfBoundsException{@inheritDoc},意思是可能产生越界,所以,AbstractSequentialList的get()就要做好对应的预防,加try或继续往上层抛异常,这里选择的是用try来防止异常的破坏。
异常链是另外一种异常体系,比如底层的异常想抛给高层,一种是刚才的方式,另外一种是如果这两个地方的异常不属于一个体系,怎么办?这种场景就适合异常链。
class Exception1 extends Exception{
}
class Exception2 extends Exception{
Exception2(Throwable throwable){
super(throwable);
}
Exception2(){
super();
}
}
class Test{
public static void main(String[] args) {
try {
a();
} catch (Exception2 e) {
e.printStackTrace();
}
}
public static void a() throws Exception2{
try {
b();
} catch (Exception1 e) {
e.printStackTrace();
throw new Exception2();
}
}
public static void b() throws Exception1{
throw new Exception1();
}
}
如果运行,我们最多只能捕获Exception2的信息,Exception1的信息,我们是不知道的,那么,怎么才能也知道Exception1的呢?我们只需要修改a()方法中的一行代码
public static void a() throws Exception2{
try {
b();
} catch (Exception1 e) {
e.printStackTrace();
throw new Exception2(e); // 这里原先是无参构造,现在是有参构造
}
}
大多数的标准异常都支持异常链的构造器,但异常也不能被乱用,应该优先根据条件方法,检查参数的有效性,去绕开一些问题,无法绕开的,再使用异常。