编写高质量代码改善java程序的151个建议——[110-117]异常及Web项目中异常处理

原创地址:http://www.cnblogs.com/Alandre/(泥沙砖瓦浆木匠),需要转载的,保留下! 文章宗旨:Talk is cheap show me the code.

大成若缺,其用不弊.大盈若冲,其用不穷.  <道德经-老子>
最完满的东西,好似有残缺一样,但它的作用永远不会衰竭;最充盈的东西,好似是空虚一样,但是它的作用是不会穷尽的

Written In The Font

摘要:

  • 异常处理概述

学习内容:

  • 建议110: 提倡异常封装
  • 建议111: 采用异常链传递异常
  • 建议112: 受检异常尽可能转化为非受检异常
  • 建议117: 多使用异常,把性能问题放一边

思考:

  • java web 中的异常处理

何为异常处理?

异常处理,英文名为exceptional handling, 是代替日渐衰落的error code方法的新法,提供error code 所未能具体的优势。异常处理分离了接收和处理错误代码。这个功能理清了编程者的思绪,也帮助代码增强了可读性,方便了维护者的阅读和理解。

java语言中,异常处理可以确保程序的健壮性,提高系统的可用率.但是java api 提供的异常都是比较低级的,所以有了'提倡异常封装’

提倡异常封装

异常封装有三个优点:  1)提高系统的友好性   2)提高性能的可维护性   3)解决java异常机制自身的缺陷

  • 提高系统的友好性

系统的友好性,就像系统和开发人员等握手与交流.好的系统对象,会展现出交流时候所需要的一切.因此,良好的友好性需要良好的代码告诉开发人员和用户.开发人员要找需要打印出堆栈信息.

show the code:

public void doStuff() throws MyBussinessException{try{InputStream iStream = new FileInputStream("无效文件.txt");}catch (FileNotFoundException e){e.printStackTrace();throw new MyBussinessException(e);//此处自定义一个MyBussinessException
        }}

::throw new MyBussinessException(e);

在这里,无效文件导致了两点:文件未找到和该业务出现问题.因此,在文件未找到之后我们可以继续根据需要告之其他异常.

  • 提高性能的可维护性

如何提搞可维护性,大家不能一味的进行这样操作,就抛出Exception,这样会导致别人看你的代码完全check不到异常点.下面的代码是不可取的:

public void doStuff()
{try{//do something} catch (Exception e){e.printStackTrace();}
}

正确的做法是对异常进行分类处理,并进行封装输出.

show the code:

public void doStuff()
{try{//do something
    }catch (FileNotFoundException e){log.info("文件未找到!文件为:xxx");}catch (SecurityException e) {log.error("无权访问,原因:xxx");e.printStackTrace();}
}

catch{}

catch{}

这样子,直接在代码层级上分析即可,代码异常在哪里抛出.维护人员看到这样的异常也会有了准确的判断.

  • 解决java异常机制自身的缺陷

先抛出个问题:例如注册时,要对很多进行检验.像密码,用户名,邮箱…...这样情况下,我们必须要在一个注册方法里面抛出很多个异常.因此,正确的方法是封装异常,建立异常容器,一次性对某对象进行校验,然后返回所有异常.

show the code

异常容器:

import java.util.ArrayList;
import java.util.List;public class MyException extends Exception
{//容纳所有异常private List<Throwable> causes = new ArrayList<Throwable>();//构造函数public MyException(List<? extends Throwable> _causes){causes.addAll(_causes);}//读取所有的异常public List<Throwable> getExceptions(){return causes;}
}

处理异常:

public static void doStuff() throws MyException
{List<Throwable> list = new ArrayList<Throwable>();//第一个逻辑片段try{//Do Something
    } catch (Exception e){list.add(e);}//第二个逻辑片段try{//Do Something two
    } catch (Exception e){list.add(e);}//检查是否有必要抛出异常if(list.size() > 0){throw new MyException(list);}
}

采用异常链传递异常

我们做的JEE项目时候,一般会有三层的结构:持久层,逻辑层,展现层.异常也是如此的,当我们各个层之间传递异常,我们就需要先封装,然后传递.简要的就是采用异常传递异常:

show the code:

[摘自源码分析]

/*** * 执行 SQL 查询。* * @param isCallable    : 是否使用 CallableStatment 执行查询* @param sql            : 查询语句* @param params        : 查询参数* @return                  结果集* */
protected List<Object[]> query(boolean isCallable, String sql, Object ... params)
{List<Object[]> result = new ArrayList<Object[]>();ResultSet rs = null;PreparedStatement pst = null;try{Connection conn = getSession();pst = JdbcUtil.prepareStatement(conn, sql, isCallable);JdbcUtil.setParameters(pst, params);rs = pst.executeQuery();int cols = rs.getMetaData().getColumnCount();while(rs.next()){Object[] objs = new Object[cols];for(int i = 0; i < cols; i++)objs[i] = rs.getObject(i + 1);result.add(objs);}}catch (SQLException e){throw new JdbcException(e);}finally{JdbcUtil.closeSqlObject(pst, rs);}return result;
}

从中我们可以抽取的看到:

catch (SQLException e){throw new JdbcException(e);}

jdbc执行SQL语句查询的时候,先抛出SQLException ,然后就像一条链一样,下一步告诉别人是JDBC的异常.下面体会经典,休息下:

大直若屈,大巧若拙,大辩若讷。躁胜寒,静胜热,清静为天下正。<道德经-老子>
最正直的东西,好似有弯曲一样;最灵巧的东西,好似最笨拙的;最卓越的辩才,好似不善言辞一样。清静克服扰动,赛冷克服暑热。清静无为才能统治天下

受检异常尽可能转化为非受检异常

所有受检异常(Checked Exception)是好事,为何要尽可能转化为非,也就是(Unchecked Exception)呢?我的理解是:受检异常威胁到系统的安全性,稳定性,可靠性,正确性时,不能转换为非受检异常.
也就是说,其中存在的受检异常有缺点,转换成Unchecked Exception就轻松解决了.

  • 受检异常使接口声明脆弱

show the code:

interface User
{//修改用户名密码,抛出安全异常public void changePass() throws MySecurityException;
}

throws MySecurityException;

这里面不一定只是一个异常,然而定义了异常,会增加了接口的不稳定性,这就存在了面向对象设计的严重亵渎,如果要改变的话,又破坏了封装性.

另外,受检异常还有两个缺点:

  • 受检异常使代码可读性降低
  • 受检异常增加了开发工作量

多使用异常,把性能问题放一边

“性能问题不是拒绝异常的借口” 就当一个常见的登录用例.我们经常会添加一个例外的事件:”连续登录3次登录失败,暂时锁定用户帐号.”这样这个例外的事件就是一个异常处理.

show the code

public void login()
{try{// 正常登录
    } catch (InvalidLoginNameException e){// 用户名无效
    }catch (InvalidPasswordException e){// 密码错误
    }catch (TooManyLoginsException e) {// 多次登录失败
    }
}

这样子一来,代码逻辑很清晰.但是这样子就抛出了一个主意.这样子有代价:

性能比较慢


java的异常处理机制确实比较慢,这个性能慢是相对的.相对那些基础类型:String Integer…等.有人测试结果如下:

测试结果:
(运行环境:xen虚拟机,5.5G内存,8核;jdk1.6.0_18)
(10个线程,创建10000000个对象所需时间)
普通Java对象         45284 MS
普通java异常        205482 MS
改进的Java业务异常   16731 MS

相当于创建每个异常对象是普通对象的五倍.但是数量级上是 MS,在一个系统中,如此微小的性能消耗是可以允许的.

java web 中的异常处理

经验之谈:”用对了地方就好,用错了地方就不好。”这是我的师傅跟我说的,他教会了很多.太很抽象,我想我会慢慢学会的.

实际J2EE项目中,通常一个页面请求到达后台以后,首先是到MVC中的controller,在controller层会调用业务逻辑层service,而在service层会调用持久层dao进而获得数据,再将获得的数据一层一层返回到controller层,然后通过controller控制层转发到指定页面.

可能存在的异常:

  • dao层可能会发生SQLException异常
  • service层可能会发生NullPointException异常,
  • controller层可能会发生IOException异常,RuntimeException异常

正确的处理方式


根据上面知识的说法:我们该用以下的方法来实现

  • 提倡异常封装
  • 采用异常链传递异常 [在这里我们举过,DAO层中jdbc操作怎么实现抛异常例子]

show the code:

@RequestMapping(value = "/courseTeacherRelationAdd")
public @ResponseBody String courseTeacherRelationAdd(String courseID,String teacherInfoID,CourseTeacherRelation courseTeacherRelation)
{try{int sign = courseTeacherRelationService.saveOrUpdateCourseTeacherRelation(courseID,teacherInfoID,courseTeacherRelation);if( sign == Constant.RESULT_SUCCESS )return successResponse("保存成功","../courseTeacherRelation/courseTeacherRelations" , "courseTeacherRelations");}catch (Exception e){throw new EntityException("Error! when save the entity",e);}return failResponse("保存失败");}

throw new EntityException("Error! when save the entity",e);

这里用了链式异常抛出:EntityException是自定义的异常类:

public class EntityException extends RuntimeException
{private static final long serialVersionUID = 1L;public EntityException() {super();}public EntityException(String message) {super(message);}public EntityException(String message, Throwable cause) {super(message, cause);}
}

自然还有些什么拦截器抛出异常,在这里就不详细展开讨论了.

Editor's Note

异常对我说:”用对了地方就好,用错了地方就不好。”

编写高质量代码改善java程序的151个建议——[110-117]异常及Web项目中异常处理相关推荐

  1. 编写高质量代码:改善Java程序的151个建议 --[106~117]

    编写高质量代码:改善Java程序的151个建议 --[106~117] 动态代理可以使代理模式更加灵活 interface Subject {// 定义一个方法public void request( ...

  2. java 151建议_编写高质量代码改善java程序的151个建议——导航开篇

    前言 系列文章: 下个星期度过这几天的奋战,会抓紧java的进阶学习.听过一句话,大哥说过,你一个月前的代码去看下,惨不忍睹是吧.确实,人和代码一样都在成长,都在变好当中.有时候只是实现功能的编程,长 ...

  3. 编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议1~5)...

                 The reasonable man adapts himself to the world; The unreasonable one persists in trying ...

  4. 博友的 编写高质量代码 改善java程序的151个建议

    编写高质量代码 改善java程序的151个建议 http://www.cnblogs.com/selene/category/876189.html 转载于:https://www.cnblogs.c ...

  5. Github即将破百万的PDF:编写高质量代码改善JAVA程序的151个建议

    代码是我们前进的基石. 废话不多说直接把本书部分内容展示出来 目录 == 第1章Java开发中通用的方法和准则/1 建议1:不要在常量和变量中出现易混淆的字母/2 建议2:莫让常量蜕变成变量12 建议 ...

  6. 转载----编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议1~5)...

    阅读目录 建议1:不要在常量和变量中出现易混淆的字母 建议2:莫让常量蜕变成变量 建议3:三元操作符的类型务必一致 建议4:避免带有变长参数的方法重载 建议5:别让null值和空值威胁到变长方法    ...

  7. 编写高质量代码:改善Java程序的151个建议(第9章:多线程和并发___建议125~131)

    建议125:优先选择线程池 建议126:适时选择不同的线程池来实现 建议127:lock与synchronized是不一样的 建议128:预防线程死锁 建议129:适当设置阻塞队列的长度 建议130: ...

  8. java代码优化的方法和准则_编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议16~20)...

    建议16:易变业务使用脚本语言编写 Java世界一直在遭受着异种语言的入侵,比如PHP,Ruby,Groovy.Javascript等,这些入侵者都有一个共同特征:全是同一类语言-----脚本语言,它 ...

  9. 转载--编写高质量代码:改善Java程序的151个建议(第1章:JAVA开发中通用的方法和准则___建议16~20)...

    阅读目录 建议16:易变业务使用脚本语言编写 建议17:慎用动态编译 建议18:避免instanceof非预期结果 建议19:断言绝对不是鸡肋 建议20:不要只替换一个类 回到顶部 建议16:易变业务 ...

最新文章

  1. python基础题-python基础练习题(一)
  2. 资源收集流程为SDN控制器
  3. 用神经网络分类集合{x|x∈x}与集合{x|x ∉x}
  4. Web开发中8个基础常见功能
  5. oracle 并行执行 杀掉会话,oracle – 为什么即使我禁用并行DML和并行DDL也会创建并行会话...
  6. 研讨会 | 知识图谱引领认知智能+
  7. 用离线编辑器Zoundry写zblog日志
  8. 【致青春】致成长路上的那些琐事
  9. 华中科技大学计算机预推免2021,华中科技大学光学与电子信息学院2021年推免预报名通知...
  10. 【idea】 Unsupported class file major version 57
  11. python中else和if的结合语句_python中else和if的结合语句_python中的if-else语句和字典...
  12. springcloud五大组件?注解_spring cloud实现简单的微服务架构
  13. C++中的namespace(using namespace)的理解
  14. 中国石油大学《测井解释与生产测井》第三阶段在线作业
  15. SeaweedFS介绍安装集群部署总结
  16. 中国双酚F树脂市场趋势报告、技术动态创新及市场预测
  17. 新型材料集成墙面,到底“新”在哪里?
  18. HTML如何引入md5算法,MD5算法实现
  19. 消失的阅读量:你家公众号还能活多久?
  20. 公司接口裸奔10年了,有必要用API接口签名验证吗?

热门文章

  1. 画图用计算机显卡,1分钟看懂显卡显卡绘图原理!
  2. MIT Cheetah Learning (一):State Estimate
  3. Java中先按照姓名排序(姓名相同)在按照年龄排序(年龄相同)按照编号 排序呢 策略模式
  4. sql将数据按照年月日分组并统计数量
  5. 测试飞机高度和速度的软件,测量飞行的高度、速度和方向
  6. 短信群发的频率应该是多少
  7. 高手支招:不用权限快速访问网络资源_jiasuba.com
  8. 哈理工计算机学院学生会技术部,信息技术学院、软件学院学生会各部门工作职责...
  9. 2.一个简单的Servlet容器
  10. mysql 创建触发器(for each row解释)