1.为什么写异常处理?
- 大多数程序员根本不懂得如何去处理异常。他们总是认为try…catch或者throw就能解决问题。
- 他们从来就没有想过他的调用者会怎么处理他处理过的这个异常。
- 我受够了这些api的调用!
2.且看我如何战五渣!
- 什么是异常?程序不正常运行产生的现象,如:参数不合法、文件未找到。正常运行是不会产生异常的!
- 异常的分类:checked Exception(编译时异常,必须显示的处理)、unchecked Exception(运行时异常RuntimeException)
- throw or try…catch ?我们先看看以下这个案例:
失败的处理方式之一:每个调用者都不得不处理,他只能增加调用者的负担,并且该处理显得毫无意义。
//基础Dao层api
public int addEntity(T t) throws Exception;
//调用者不得不显示的处理这个异常,尽管这种操作毫无意义
public int addUser(User user){
try{
return dao.addEntity(user);
}catch(Exception exception){
//诸位,想一想你在这个地方能做什么操作 ?
logger.error("add user error:"+exception...);
}
//这个-1难道这比直接抛出异常更有意义?
return -1;
}
失败的处理方式之二 : 提供调用者根本无法处理的异常。
public int addUser(User user){
try{
DaoHelper.sql.beginTranction();//api抛出异常
//执行语句DaoHelper.sql.insert(.....);//api竟然也抛出异常
DaoHelper.sql.commitTranction();//api抛出异常
}catch(SqlException exception){
try{
DaoHelper.sql.rollBackTranction();//api抛出异常
}catch(SqlException exception){
//我实在不知道该在这个地方怎么处理 !!!
}
}finally{
try{
DaoHelper.sql.endTranctiuon();//api抛出异常
}catch(SqlException exception){
//我实在不知道该在这个地方怎么处理!!!
}
}
//我都不知道返回值怎么写了
}
这是我见过最傻逼的异常处理方式,没有之一。每一个DaoHelper都抛出异常,什么业务都没写,这些代码必不可少,他不但给调用者带来负担,而且给调用者带来困惑:我要做什么?我能做什么?DaoHelper.sql.rollBackTranction()抛出异常如何处理?这是目前一大互联网公司的真实代码!每一个员工的dao层方法必有以上10行代码!
失败的处理方式之三 : 调用者找不到异常发生的地方。
//这个比较少见,在我的职业生涯中也就碰到过那么一次(我在调试时始终找不到正确的地方),但是具有警示意义:那就是如果你不知道如何去处理这个异常,请不要去包装这个异常
public int addUser(User user){
try{
userDao.addUser(user);//产生RuntimeException
}catch(Exception exception){
throw new Exception("用户插入失败!");//异常本来发生的地方就被埋没了,如果userDao.addUser(user)的异常是层层上抛了三次就更加可悲了!
}
}
失败的处理方式之四 : 你真的需要自定义异常?
- 很多同志都说,我们来个自定义异常吧。我实在想不通为什么要这么做?因为在我有限的编程生涯中唯一想到的就是警示业务运行出现错误!如:throw new OrderNotFoundException();这样做比返回null 更有意义吗?throw new BadManException() ?用异常来控制业务流程,你必须一开始就对业务作出技术规划!
- 难道仅仅是因为你掌握了throw这个关键字,或者你也想这么做:throw new BadCredentialException();
其他的异常处理方式太过简单就不再提起,因为对渣渣程序员来说不会犯那些try..catch 而又毫无动作的错误。
3.重要点
异常处理的关键之处在于:当你决定处理这个异常时,你的调用者会怎么办!
- 不要在dao中抛出checked Exception,不要在dao中捕获RuntimeException!
- 不要轻易抛出checked Exception,除非你认为调用者必须处理!
- 不要在只读操作中轻易抛出RuntimeException 例如:
throw new RuntimeException("数据不存在");
可以修改为return null ; 或者 return Collections.emptyList();
- 如果你认为调用者不能通过try…catch来处理此操作,请务必使用RuntimeException。避免程序必定正常运行的资源被错误的处理了,否则try…catch跑到线上就完蛋了!例如:
throw new RuntimeException("jdbc.properties不存在")
;
一个好的api不但给调用者带来便利,还直接影响着调用者的技术。因为他总是不得不去配合这个api以改变自己的代码,使自己逐渐成为一个合格的渣渣。