`

异常处理的艺术(总结)

阅读更多

  在看一些项目源码中,突然发现了异常的处理也是一门比较大的学问,其实处处都有学问,只是你是否留意而已。。好了,少点啰嗦,关于异常的处理,je上有个很精彩的讨论,我花了快一个钟时间才看完了,确实值得一看,帖子的网址:http://www.iteye.com/topic/2038 

  当然我这里写的,只是一个纯属的建议,大都是看了网上的帖子后,总结的。都是些前辈的经验。。下面开始吧。

——————————————————————————————————————————————

Java异常有三类:错误,运行时异常,检查型异常。

 

官方的观点是

39 条:最好为异常条件使用异常。也就是说,最好不为控制流使用异常。

40 条:为可恢复的条件使用检查型异常,为编程错误使用运行时异常。

41 条:避免不必要的使用检查型异常。

43 条:抛出与抽象相适应的异常。(使处理异常更直观)

在异常的使用上,专家的观点是很不一样的

C#作者Anders根本就忽略检查型异常。

Bruce Eckel,声称在使用 Java 语言多年后,他已经得出这样的结论,认为检查型异常是一个错误 —— 一个应该被声明为失败的试验。

——————————————————————————————————————————————

缺点:

缺点1,代码中包含了过多的catch,使得代码不清晰

缺点2,有时候捕捉的异常没有什么实际意义

缺点3,不够清晰的错误指示。

缺点4,过深的异常层次。

缺点4,性能。

——————————————————————————————————————————————

Eckel 提倡将所有的异常都作为非检查型的,并且提供将检查型异常转变为非检查型异常的一个方法,同时保留当异常从栈向上扩散时捕获特定类型的异常的能力

 

Rod Johnson 他采取一个不太激进的方法。他列举了异常的多个类别,并且为每个类别确定一个策略。一些异常本质上是次要的返回代码(它通常指示违反业务规则),而一些异常则是发生某种可怕错误(例如数据库连接失败)的变种。Johnson 提倡对于第一种类别的异常(可选的返回代码)使用检查型异常,而对于后者使用运行时异常。在发生某种可怕错误的类别中,其动机是简单地认识到没有调用者能够有效地处理该异常,因此它也可能以各种方式沿着栈向上扩散而对于中间代码的影响保持最小(并且最小化异常淹没的可能性)。

——————————————————————————————————————————————

解决1:谨慎的抛出检查型异常。或者你认为,你可以处理它。否则,包装为运行时异常。

解决2:如果遵守12不是问题

解决3:异常不跨层,否则必须捕捉或者包装。

         比如持久层丢出的SalException,你或者丢弃/处理/包装(为运行时异常),或者重新包装为业务层异常。保持JEE层的独立和异常的清晰性。

         包装底层异常,保持异常链。

解决4:如果符合14也不是问题。再次强调,能捕捉就捕捉。

解决5:减少异常使用,减少层次。

—————————————————————————————————————————————— 

je里面讨论,在上面的网址可找到:

 

robin认为异常是流程控制的一部分——当然,考虑到性能问题,这个流程不应该是大概率流程——也就是异常流程

例如用户登录

 

User login(String username, String password); throws UserNotFoundException, PasswordNotMatchException; 
try {
UserManager.login(xx,xx);
 .... 用户登陆以后的主事件流代码 
} catch (UserNotFoundException e){ 
... 用户名称没有的事件处理,例如产生一个提示用户注册的页面 
} catch (PasswordNotMatchException e){
 .... 密码不对的事件处理,例如forward到重新登陆的页面 
}

 

 

Potian则认为,没有用户是正常业务逻辑的一部分

If(!用户业务层.没有这个用户(用户名))错误提示界面;

If(用户业务层.检验密码(用户名,密码))登录成功;

else 登录失败;

Potian认为不应该在一个业务中包含了过多的责任。

 

muziq认为:

    从做应用的角度看,我希望利用异常来管理显示在用户面前的错误提示,这样我就会将异常划分为两类,一类是可以显示给用户看的,或者说用户可以看的懂的,一类是给维护人员看的,就是通常说的系统错误,可以想象,让用户看到“空指针异常”是极不友好的行为。我们的项目中有一个专门显示错误的页面,它要么显示有具体业务含义的错误,要么就显示“系统错误”(然后维护人员可以从log中查找错误)。而前一类错误里面,每种错误总有一个不同的异常类和它对应,或者说,业务逻辑方法向表示逻辑抛出的异常,表示逻辑不需要分别处理(不要显示错误的除外),一律交给错误页面(其实是ErrorPageUIAction,我们用Struts),错误页面看是什么异常就显示什么错误提示,这里错误页面需要一个XML,XML里面定义了异常和错误提示的对应关系,当然XML里面只能有用户异常,不在XML里面的异常错误页面就会显示“系统错误”。业务逻辑事先将用户异常登记到XML中,这样错误信息还可以单独、统一的维护。 
    上面讲的是将异常展示到错误页面的方法,这其实只涉及到最后一层(Action)捕捉异常和业务逻辑层抛出异常的问题,而如何中间层内的异常如何抛、如何捕捉的问题考虑的思路一定是不一样的,不过,做应用系统的,业务逻辑层内部交叉引用的不多,所以这一块异常设计的矛盾并不突出。而如果你正在开发高度重用的组件甚至框架,异常就一定要好好设计一下了。 
    至于组件、框架的异常如何设计,我想只要去学JDK、Hibernate的那一套东西就没错了。能想到的就是,异常一定是调用者可以理解的,和方法的语义密切相关的。

—————————————————————————————————————————————— 

一些网上人的评论:

    在servlet中,我喜欢仅仅简单的在action中调用最好一个业务层方法就可以完成此action的任务。这意味着我的servlet非常瘦,可以比较容易的被替换。如果采用了potian的办法,则意味着我要把业务层中的代码前移到servlet中来,这模糊了业务层的责任。解决的办法是回到老路子上来。

    我还认为,没有异常的业务方法表达能力太弱,异常给了他们更丰富的表达能力。这使得业务层可以更丰富的表达业务意义。避免将业务责任分散掉。

———————————————————————————————————————————————

我的个人偏向:

  我个人比较偏向je上muziq 的看法,项目的最终用户是网民,而大都不是计算机专业者,所以不管异常怎么处理,都要对用户有个友好的提示,尽力少,尽量简单。而对于程序设计者来讲又必须依据异常对程序进行修复处理。所以异常一般分为两类:一类是可以显示给用户看的,或者说用户可以看的懂的;一类是给维护人员看的。这是对于异常在程序表面上的处理。

  而对于程序设计的底层(即代码的设计),异常尽量往高层抛出,让高层进行统一的处理,当然这是对于检查型异常而言。

  如果一个异常是致命的,不可恢复的。或者调用者去捕获它没有任何益处,使用unChecked异常。

  如果一个异常是可以恢复的,可以被调用者正确处理的,使用checked异常

  在使用unChecked异常时,必须在在方法声明中详细的说明该方法可能会抛出的unChekced异常。由调用者自己去决定是否捕获

 

相关的讨论比较好的帖子:http://www.iteye.com/topic/72170

 

文笔比较差,加上实际经验比较少,很难描述,还是看看代码比较容易懂,该实例是结合了ssh2:

      

Dao层:不抛出检查型异常,都由Hibernate包装成了运行期异常了

 

 

package dao; import dao.base.BaseDao; import model.User; 
public interface UserDao extends BaseDao<User,Integer>{
   public void addUser(User user); 
   public User getUser(String id); 
}

 

Dao 的实现层不写了,继承HibernateDaoSupport,由它实现,把异常都包装成运行期异常了。

 

service 层:抛出XXXService类对应的XXXException 异常

package service; import java.util.List; 
import exception.UserException;
import bean.User; 
public interface UserManager {
 public void addUser(User user) throws UserException;
 public User getUser(String id) throws UserException;
}

 

 Service 实现层:抛出XXXService类对应的XXXException 异常

public class UserServiceImp implements UserService {
 static Logger log=Logger.getLogger( UserServiceImp.class.getName());
 private UserDao userDao;
 @Override public User addUser(User user) throws UserException   
 {    
   try{
   ........ 
  }catch(Exception e){
   //用日志记录错误信息 log.debug(e.getMessage()); 
  //重新抛出新的异常,因为用户没必要知道详细的底层异常信息 
   throw new UserException("验证用户登陆出现错误,请重试"); 
 }
 。。。。setXXX()。。。。。
 }

 

action 层:如果action 不处理UserException异常,则继续抛出,由拦截器拦截

 

public class AddUserAction extends BaseAction {
 private String name;
 private String password;
 public String execute() throws Exception{
 //如果action 不处理UserException异常,则继续抛出,由拦截器拦截 
 } 
}

 

Struts2 配置文件:利用配置文件,把相应的异常转向相应的页面。

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
	<constant name="struts.i18n.encoding" value="GBK"></constant>
	<package name="struts" extends="struts-default">
		<global-results>
			<result name="XXXException">/error.jsp</result>
		</global-results>
		<global-results>
			<result name="userException">/error.jsp</result>
		</global-results>
		<global-exception-mappings>
			<exception-mapping exception="exception.XXXException"
				result="XXXException" />
		</global-exception-mappings>
		<global-exception-mappings>
			<exception-mapping exception="exception.UserException"
				result="userException" />
		</global-exception-mappings>
		<action name="addUser" class="action.AddUserAction">
			<result name="input">/WEB-INF/jsp/addUser.jsp</result>
			<result name="success">/WEB-INF/jsp/main.jsp</result>
			<result name="failure">/WEB-INF/jsp/addUser.jsp</result>
		</action>
	</package>
</struts>

 

1
0
分享到:
评论

相关推荐

    JavaScript 异常处理 详解

    总结来说,JavaScript异常处理是一门艺术,需要开发者对异步编程和错误处理机制有深刻的理解。异常处理不仅能够提升程序的健壮性,减少用户的困扰,还能帮助开发者更好地定位和修复程序中的漏洞,从而提供更加流畅和...

    Java编程艺术的代码

    3. **异常处理**:Java提供了一套强大的异常处理机制,通过try-catch-finally语句块来捕获和处理运行时错误。书中源代码可能会包含各种异常处理场景,有助于理解何时及如何使用异常处理。 4. **集合框架**:Java...

    Android开发艺术探索.pdf

    ### 总结 《Android开发艺术探索》是一本旨在帮助开发者提升Android应用开发水平的书籍,内容涵盖了从基础知识点到高级技术应用的诸多方面,对Android系统的深入理解以及各种高级技术的详细讲解,对任何想成为高级...

    程序员编程艺术第一~二十七章集锦与总结(教你如何编程)by_July-带书签目录超清文字版

    理解如何通过异常处理来捕获和处理程序运行时的问题,以及如何使用调试工具来定位和修复错误,能显著提高开发效率。 最后,第二十五章至第二十七章可能涵盖了软件工程的相关话题,如版本控制、测试策略、项目管理和...

    错误处理的基础指南

    ### 错误处理的基础指南 ...通过这些深入的讨论,我们可以看到错误处理不仅仅是一项技术活动,更是一种艺术形式,它要求开发者具备细致入微的观察力和创造力。希望本文档能为您的编程之旅提供有价值的指导和支持。

    Java语言的科学与艺术(二)

    通过对面向对象编程、内存管理、异常处理、并发编程等方面的学习,开发者不仅可以掌握Java语言的核心技术,还能了解如何运用这些技术解决实际问题,提升软件工程能力。无论是初学者还是有一定经验的开发者,都能从中...

    程序员编程艺术第一_二十七章集锦与总结(教你如何编程).rar

    随着章节的深入,读者将接触到软件工程的原则,如模块化设计、面向对象编程、异常处理和调试技术。这些章节将帮助读者学会如何组织代码,使其更具可读性和可扩展性,这对于大型项目的开发至关重要。此外,作者可能会...

    UNIX编程艺术(中文).pdf

    尽管文档链接并未提供具体章节或内容概述,但从标题“UNIX编程艺术(中文)”以及部分描述中提到的“原来linux里面命令的输出能够成为另一个命令的输入”,我们可以归纳总结出一些关键的UNIX编程概念和技巧。...

    java 大数据处理 入门

    学习Java的基础语法、类库和异常处理是掌握大数据处理的前提。 2. **大数据**:大数据是指海量、高增长速率和多样化的信息资源。它涉及到数据的采集、存储、处理和分析。Java在大数据领域中的应用包括MapReduce编程...

    Oracle 11g Pro C/C++编程艺术

    连接管理包括打开连接、关闭连接以及异常处理等功能。在Pro*C/C++中,这些操作通常通过调用特定的API来实现。例如,`sqlcoci`函数用于打开连接,而`sqlcodci`则用于关闭连接。 #### 四、SQL语句的执行 **4.1 声明...

    软件框架设计的艺术

    8. **错误处理与日志记录**:良好的框架应具备完善的异常处理机制,并提供日志记录接口,以便于调试和监控。 9. **性能优化**:C#的特性如Just-In-Time编译(JIT)、垃圾回收(GC)以及内存管理策略,有助于在框架...

    精彩编程与编程技巧-在VB中使用艺术字...

    - 注意代码的异常处理,避免程序崩溃。 - 对于更复杂的应用场景,可以考虑使用更高级的图形库或者第三方控件来增强艺术字的功能性和美观性。 通过本文的学习,读者不仅能够掌握如何在VB中使用WordArt,还能了解OLE...

    艺术品拍卖公司机构构成和工作流程(PPT38页).pptx

    4. 定期对艺术品进行检查,发现任何异常情况如锈蚀、裂痕等应及时处理,并记录在案。 5. 建立健全艺术品的保险制度,为高价值的艺术品购买保险,以减轻可能的经济损失。 6. 在拍卖前的展览阶段,需制定严格的参观...

    在线字体转换文字生成艺术字系统源码-支持自己添加字体在线艺术字.txt

    - **错误处理机制**:建立完善的异常处理流程,提升系统鲁棒性。 #### 三、核心功能模块 1. **字体上传模块**: - 允许用户上传TTF或OTF等格式的字体文件。 - 对上传的字体文件进行有效性检测,确保格式正确且...

    C++编程艺术(pdg格式)

    5. **异常处理**:C++的异常处理机制允许在程序运行时捕获和处理错误,提高程序的健壮性。书中会讲解何时、如何抛出和捕获异常,以及异常安全的编程原则。 6. **内存管理**:C++提供了对内存的直接控制,包括动态...

    Oracle.11g.Pro﹡C.C.编程艺术

    书中详细讲解了如何建立数据库连接、如何配置网络环境、如何管理用户会话以及如何处理异常和错误。 3. **数据处理**:数据是数据库应用的核心。本书在这一部分着重介绍了如何使用游标在Pro*C/C++中执行SQL查询和...

    基于ssm+Java Web的大学生艺术节管理系统.zip

    4. 异常处理:设置全局异常处理器,保证系统在遇到错误时能给出友好的提示信息,而不是直接报错。 5. 测试:进行单元测试和集成测试,确保每个功能模块的正确运行。 在微信小程序方面,开发者需要熟悉微信小程序的...

    oracle 9i 10g编程艺术

    在9i中,PL/SQL得到了增强,支持更高级别的编程,包括异常处理和面向对象编程。此外,9i还提升了数据库的可用性和可管理性,例如通过Real Application Clusters (RAC)实现了多节点集群环境。 二、Oracle 10g概述 ...

    实用图像处理类

    在IT领域,图像处理是一项广泛应用于各种场景的关键技术,包括计算机视觉、图像分析、游戏开发、数字艺术等。本主题将深入探讨一个专门处理RLE8压缩BMP图像的实用图像处理类,该类是用C++编程语言实现的。 首先,让...

Global site tag (gtag.js) - Google Analytics