一、Exception和Error的区别
在Java中我们可以这样区分,异常(Exception)是一种非程序原因的操作失败(Failure),而错误(Error)则意味着程序有缺陷(Bug)。
二、Java的类继承体系非常清楚地区分了Exception和Error
java.lang.Object
java.lang.Throwable
java.lang.Error
java.lang.Exception
一般情况下不应该尝试用catch(Throwable)或者catch(Error)去捕获Error。
三、声明异常和未声明异常的区别
1、从本质上将:在方法签名上声明的异常属于方法接口的一部分,它和方法的返回值处于同一抽象层次,不随具体实现的变化而改变。
在方法签名上声明要抛出的异常,属于这个方法接口层面的一种失败情况,简答的说就是,不管方法的内部采用什么实现,都必然存在方法内部产生方法签名上声明的异常的情况,所以这时把这个异常声明出来就非常合理。
2、下面有个相反的例子:
从帐户a向帐户b转账的transfer方法:
public boolean transfer(Account a, Account b, Money money) throws SQLException
它抛出SQLException就不对了,因为SQLException不属于这个transfer接口层面的概念,而属于具体实现,很有可能未来某个实现不用SQL了那么这个异常也就不存在了。这种情况下,就应该捕获SQLException,然后抛出自定义异常TransferException,其中TransferException可以定义几种和业务相关的典型错误情况,比如金额不足,帐户失效,通信故障,同时它还可以引用SQLException作为触发原因(Cause)。
public boolean transfer(Account a, Account b, Money money) throws TransferException {
try {
...
executeSQL(...);
} catch (SQLException e) {
throw new TransferException("...", e);
}
}
对上面这个反例的总结:
如果一个异常不属于方法接口层面,而与方法内部的具体实现相关,很有可能在未来某个实现不会产生这种异常,在这种情况下,就应该在方法内部实现中抛出这种异常。
3、简单的总结声明异常和未声明异常的区别:
1.声明异常:
在方法签名上抛出的;
属于方法接口层面,和方法内部的具体实现没有相关。
2.未声明异常:
在方法内部实现中抛出的;
与方法的具体实现相关,有可能随着不同实现而出现或消失。
4、什么情况下方法应该抛出未声明的异常?
抛出未声明异常表示遇到了和具体实现相关的运行时错误,它不是在设计时就考虑到的方法接口的一部分。
四、如何捕获其它方法抛出的异常
下面例子中方法g声明了GException,方法f声明了FException,而f在调用g的时候不管三七二十一通过catch (Exception e)捕获了所有的异常。
void g() throws GException
void f() throws FException {
try {
g();
} catch (Exception e) {
...
}
....
}
这种做法是很多人的习惯性写法,但这种写法是有问题的。问题在于g明明已经告诉你除了GException外,如果抛出未声明的RuntimeException就表示遇到了错误,很可能是程序有Bug,这时f还不顾一切继续带着Bug跑。所以,除非有特殊理由,对具体情况做了分析判断,一般不捕获未声明异常,让它直接抛出;只捕获其它方法的声明异常。
优雅的处理办法应该像下面这样:
void g() throws GException
void f() throws FException {
try {
g();
} catch (GException e) {
...
}
....
}
五、Exception和RuntimeException的区别
Java中区分Checked Exception和Unchecked Exception,前者继承于Exception,后者继承于RuntimeException。Unchecked Exception和Runtime Exception在Java中常常是指同一个意思。
Java编译器对Checked Exception的约束包括两方面:
1.对于方法编写者来讲,Checked Exception必须在方法签名上声明;
2.对于方法调用者来讲,调用抛出Checked Exception的方法必须用try-catch捕获异常或者继续声明抛出。
相反,Unchecked Exception则不需要显式声明,也不强制捕获。
六、自定义异常应继承Exception还是RuntimeException?
对于自己编写的异常类来讲,推荐默认的是继承RuntimeException,除非有特殊理由才继承Exception。
这种推荐的做法的设计理念:把是否捕获和何时捕获这个问题交给使用者决定,不强制使用者。
当然,如果某些情况下明确提醒捕获更加重要还是可以采用Checked Exception的。