大家经常在讨论业务中如何使用异常,异常的性能如何等。
第一个问题 : uncheck 异常,check 异常 异常使用的原则
1、如果调用者有责任在调用前检查必要状态,但没检查,就抛出uncheck异常
一般要提供给调用者判断方法,如果他不调用,则是一个编程错误,就应该使用uncheck异常
private float balance;
/**
* <pre>
* 在扣款前调用本方法判断
* </pre>
* @param amount
* @return true 可以消费,false 余额不够
*/
boolean canConsume(float amount){
return balance > amount ? true : false;
}
/**<pre>
* 消费扣款
* 在使用前,要判断余额是否够,
* 调用canConsume(float amount)
* </pre>
* @param amount 消费金额,正数
*/
void consume(float amount){
if(amount > balance ) throw new IllegalArgumentException("amount too large");
balance -= amount;
}
void invoke(){
if(canConsume(50)){
consume(50);
}
}
2、如果是不调用者责任,而是本函数的责任,就必须声明抛出异常,check异常。
/**<pre>
* 消费扣款
* 在使用前,要判断余额是否够,
* 调用canConsume(float amount)
* </pre>
* @param amount 消费金额,正数
* @throws BalanceException 余额不足
*/
void consume(float amount) throws BalanceException{
if(amount > balance ) throw new BalanceException("amount too large");
balance -= amount;
}
void invoke(){
try {
consume(500);//消费
sendGift();//配送礼品
} catch (Exception e) {
// TODO: handle exception
notifyBalanceLack();//通知余额不足
}
}
第一个问题 : 异常是否影响性能
异常肯定影响性能。
实例化异常时,要调用超类Throwable中的 public synchronized native Throwable fillInStackTrace();
填充线程调用堆栈,这个方法是同步的,肯定影响性能。
如果业务异常不需要堆栈信息,可以覆盖:
@Override
public Throwable fillInStackTrace() {
return this;
}
我做了一个测试,并发线程10个,每个线程生成10000000个普通对象,一般异常,和覆写了不带同步的fillInStackTrace()的异常,时间是:
普通对象: 89673 毫秒
一般异常: 568413 毫秒
覆写fillInStackTrace()异常: 40424 毫秒
很明显,覆写fillInStackTrace()异常 性能最高。