`
阅读更多
在面向对象的应用程序中,由于代码重载、错误的问题处理方式,导致异常有越来越多的趋势。在这篇文章中,作者Jean-Pierre Norguet介绍了如何设计异常,来实现一个简单的、可读的、健壮的、灵活的、面向调试的及用户友好的错误处理系统。在本文中,作者提出了简单异常集合的设计,并且给出了Java实现的源代码。最后,作者介绍了如何将这样的设计集成到一个Java的企业应用程序中。

     在一个面向对象的项目中,设计异常处理的最好途径从来也没有如我们期待的那样清晰。在旧的大的系统中,异常的发生有激增的趋势,最终达到几百行的代码。对于一些常见的编程场景,异常检查是必须的,但是也会带来可观的处理开销。虽然安静的异常捕获可以找到问题的源头,但是避免不了它的一些缺点(虽然这些缺点不是致命的);比如你必须熟悉这些代码。



       本文将介绍如何通过有限的异常集合来满足一个错误处理的需求。在建立起一个好的错误处理系统框架之后,将会指出异常处理设计中常见的错误,这些错误将会逐渐损害应用程序的性能;然后将会给出一个异常集合的例子,这个例子支持本文讨论的异常处理设计的基本功能:异常系统应该被设计成能够帮助外部系统(用户)处理未知情况(在运行时发生),而不是设计成能够帮助编程人员处理已知情况;还会介绍本文给出例子中的各个类的含义以及如何在一个特定的Java企业应用程序体系中使用它们;最后给出这个例子的Java实现。
错误处理需求

什么是一个好的错误处理系统?抛开审美角度的考虑,一个好的错误处理系统通常要符合下面的条件:
1、任何异常都不会导致应用系统的崩溃。
2、在发生异常时,允许应用程序进行相应的处理。
3、显示给用户的错误信息要清晰的描述发生了什么错误以及应该采取什么样的处理。
4、如果需要辅助信息,错误信息还要帮助用户与帮助部门交互,为帮助部门团队提供必要的信息,
    使他们能够快速的容易的重现错误。

5、日志信息能为开发团队人员在识别错误、在应用程序代码中定位错误产生的位置以及修正错误提供必要的信息。

6、错误处理代码不会降低应用程序代码的可读性。必要的时候,错误处理仅仅是一个安全网,它对应用程序的核心功能具
    有较低的访问权限。

     一个错误处理系统的设计符合这些条件才能被认为是完整的。对于大多数Java开发人员来说接下来的问题就是:如何灵活的使用异常类来设计一个错误处理系统,而不是通过简单的重载它们来实现。
应该避免的常见用法

可以通过一个有限的异常类集合来满足上面提到的需求。当设计这样的一个异常类集合时,你应该避免一些常见的用法,例如:
1、对每个问题都定义的异常类,这样会导致系统中异常类的激增。
2、对每个包定义一个异常类集合,这没什么用处而且也会导致系统中异常类的激增。
3、对每个异常都提供checked和non-checked两个版本,引入了检测异常开销。异常语义的后续副本也会混淆异常处理的设计。
4、最后,抛出和捕获通用异常在很多方面也是错误倾向。

      本文下面提到的异常类集合按照错误处理语义分类,避免了异常处理相关的常见问题。尤其是在应用程序的规模和复杂程度增长是,这种方式更值得推荐。
异常处理设计

图1展示了异常类集合的设计,这个设计避免了异常类激增、检测异常开销和异常的安静捕获。

图1.一个异常类集合的例子

    在这个图中你会发现有些异常是checked,而有些是runtime。为了避免异常抛出声明的开销,checked异常基于下面两个目的被保留下来:

   1. 告诉调用方法,在这个处理过程中发生了一个可预见的意外情况。在这种情况下,问题的语义已经被处理方法定义了,直接捕获会更好。
   2. 告诉外部系统发生了一个未解决的问题,需要根据异常语义来处理这个问题。

理解异常语义

     在这里阐明本文对异常语义的定义。在作者看来,设计对象的类需要根据它们在现实世界中的等价物。一个水果或者一个人很容易设计成一个Java对象类。但是异常设计却不同:因为一个水果或者一个人在现实世界中非常直观,异常却不同。实际上,上面的两类异常中,只有第一类在现实世界中存在;而第二类异常模拟了系统执行过程中会发生什么错误,因此在系统之外就不存在了。直接捕获因此也只对第一类异常适合。

    作者的设计建议就是异常应该根据它们的目的来设计。系统内部的、自我调整的异常就意味着是帮助系统来处理不可预见的情况。这些异常的目的也就不是模拟系统中的问题,而是给一个系统需要采取什么措施的指示。
一个异常类集合的例子

在图1中你可以看到四类异常对应四类处理,如下:

   1. BusinessException:一种异常情况发生。这种情况是可预见的,也可以被调用方法检测到并立即采取措施。
   2. ParameterException:输入的数据对处理过程不合法。用户被要求重新输入有效数据或者修改处理过程的条件。
   3. TechnicalException:技术问题,如无效的SQL语句。这种情况下,请求操作未完成。用户需要和帮助部门联系,调查问题的原因;或者尝试其它的服务。对使用系统的其它用户没有影响。
   4. CriticalTechnicalException:技术问题,如数据库崩溃。用户被建议稍后重试。在问题修复前,所有的用户都不能使用系统。

     这个异常类集合只是一个例子;很多异常类集合都可以参照它来定义。例如,TechnicalException和 CriticalTechnicalException可以被设计成一个类,这个类声明一个severity布尔属性。重要的是关注采取什么处理措施而不是什么问题引起异常。
异常日志记录

     虽然异常语义关注采取的措施,但是出现的问题也很重要。例如,开发团队人员可以使用这些信息调试代码。在异常处理设计中,导致异常的信息能够在以用程序的错误日志中发现。在适当的位置使用一个好的日志记录框架,这个框架能够有效的从异常信息和堆栈跟踪中记录问题信息。

    剩下的唯一问题就是怎么样设计异常类使之能够方便的返回信息。一个解决方案就是为异常类声明一个id属性来代表遇到的问题的种类。另外,问题自身可带有通用异常,也就是把通用异常内嵌到应用程序异常中。在捕获的时候,原始的信息和堆栈跟踪信息能够通过内嵌的异常得到。id属性和内嵌异常是包装问题的两种途径。
异常处理流程的设计

     一旦你已经设计好异常类本身了,下一步需要思考的就是它在应用程序中的处理流程。一个标准的JEE应用程序体系通常包括四个部分:展现、业务、集成、持久。异常经常在集成和持久部分被抛出。在业务部分,里层的捕获checked异常,而外层捕获runtime异常并根据它们的类型来采取相应的处理措施。也可以在业务部分抛出一些checked异常并且捕获它们。在这种模式下,集成和持久部分,包括业务部分的里层都将runtime异常转化成具体的处理措施。图2展示的就是一个典型的JEE应用程序异常处理流程。

图2.标准JEE包体系中异常的处理流程

     异常抛出路径是指从持久部分(假设)发生问题到问题被解决所经历的流程。如果持久层的调用方法能够解决这个问题,那么这个异常就直接被捕获并采取相应的处理措施,业务流程一切照常;如果问题不能被解决,异常将内嵌到一个runtime异常中经过业务部分的中间层传递到应用程序的上层中,在这里,典型的处理方法就是使用一些应用程序控制器来捕获这些runtime异常并采取相应的处理措施,展现层显示相应的错误信息给用户。直接捕获checked 异常和推迟捕获runtime异常是异常处理设计中的两种主要方案,如图3所示。


图3.直接捕获checked异常和推迟捕获runtime异常
扩展java.lang.Exception

     文中提到的异常处理设计方案在任何的面向对象语言中都可以很容易的实现,包括Java。一个相似的异常类树已经在标准Java库中提供了。在这个库中异常被设计为java.lang.Throwable,ckeched异常被设计为java.lang.Exception,runtime异常被设计为 java.lang.RuntimeException。

    在java.lang.Exception下,有大量泛语义的业务异常。运行时应用程序异常,如ParamterException、 TechnicalException、CriticalTechnicalException(见图1)各自都设计成相应的概要异常,如 IllegalArgumentException、MissingResourceException、IllegalStateException。

    在应用程序中,重用Java标准异常是一个不错的主意,但是由Java标准类抛出的异常也会导致一些混乱。你可以通过扩展 java.lang.Exception自定义异常类树来避免这样的混乱。通过自定义的异常类树,你还可以实现内嵌异常和问题ID。列表1给出了文中例子的Java代码实现。注意,它包括内嵌异常和问题ID。

列表1.通过Java代码实现内嵌异常和问题ID
public class NestedException extends RuntimeException {
  protected Exception nestedException;
  protected int issueId;
  public NestedException(String msg, Exception e, int id) {
    super(msg);
    this.nestedException = e;
    this.issueId = id;
  }

public Exception getNestedException() {
  return this.nestedException;
}
public int getIssue() {
  return this.issueId;
}
}

public interface Issue {
  public final static int UNDEFINED = 0;
  public final static int EXTERNAL_SERVICE_1_DOWN = 1;
  public final static int EXTERNAL_SERVICE_2_DOWN = 2;
  public final static int SQL_STATEMENT_ERROR = 3;
// ...
}
总结

     设计一个满足好的错误处理系统需求的异常类树非常简单。简单的秘诀就是将设计的主要精力集中在系统应该采取什么样的处理措施,而不是关注会出现的什么样的问题。在本文的设计当中,问题的信息封装在异常类里面。通过在处理措施和问题之间分配异常语义,让你将异常类树限制在一个有限的异常类集合中(可能就六七个左右)。这种设计不仅限制了异常类激增,保证代码的可读性,使你在以后的开发中以最佳的清晰度来关注应用程序的业务逻辑的编码。
作者简介

   Jean-Pierre Norguet拥有布鲁塞尔大学的计算机科学和网络工程博士学位。在IBM经过了三年全职的电子商务应用程序关键任务的Java开发后,作为团队领导者和教练,他擅长的技术领域包括了整个应用程序开发周期。目前专注于Java技术、实体集成和迷你Web应用的研究。除了一些在线Java文章外, Norguet博士还与Prentice、IBM出版社一起出版了有关JEE的著作,同时还在ACM、IEEE和Springer-Verlag的国际研讨会发表了一些文章。他的业务兴趣还包括艺术绘画、兼职法语教师和临时健康顾问。
  • 大小: 11.5 KB
  • 大小: 6.5 KB
  • 大小: 12 KB
分享到:
评论
1 楼 ivonxiao 2008-05-08  
谢谢楼主的分享

相关推荐

    TIPTOP_异常管理系统.pdf

    TIPTOP_异常管理系统培训教育手册,内容包含:系统接口、基础数据、异动作业、报表简介、等相关内容。给有需要的人。

    图书馆管理系统C++

    本文将深入探讨C++在图书馆管理系统中的应用以及异常处理在系统设计中的重要性。 一、C++语言基础 C++是一种面向对象的编程语言,它的特点是性能高、灵活性强,特别适合开发大型、复杂的系统。在图书馆管理系统中...

    面向对象--员工管理系统(异常).rar

    在这个"员工管理系统(异常)"项目中,我们可以看到几个关键的类:Main.java、Employee.java、MyComparator.java和Department.java,它们共同构建了一个能够处理员工信息并具备异常处理功能的系统。 首先,`...

    异常处理.doc

    本文作者Jean-Pierre Norguet探讨了如何设计异常管理系统,以实现简单、可读、健壮、灵活、面向调试和用户友好的错误处理。 首先,异常处理的目的是防止程序因未预期的错误而崩溃,并在出现异常时提供适当的反馈和...

    JAVA开发的图书管理系统

    《JAVA开发的图书管理系统详解》 图书管理系统是信息化建设中的重要组成部分,它旨在方便图书馆的日常运营,提高图书管理效率,实现对图书的自动化、数字化管理。本系统采用JAVA语言进行开发,尤其利用了JAVA的...

    仓库管理系统源码+仓库管理系统源码

    仓库管理系统源码是用于实现企业或组织内部仓库管理信息化的重要工具。这个系统涵盖了库存控制、物品出入库记录、库存盘点、库存预警等多个功能模块,旨在提高仓库作业效率,减少库存成本,确保库存数据的准确性和...

    No.11 异常相关指令的实现1

    在计算机体系结构中,异常处理是一项关键功能,它允许处理器响应不同类型的中断、陷阱和系统调用等事件,中断或...通过理解这些概念和处理流程,我们可以更好地设计和优化处理器的异常管理系统,从而提高整体系统性能。

    教务管理系统 流程图教务管理系统 流程图

    教务管理系统是高等教育机构中不可或缺的一部分,它负责高效地组织和管理教学活动。流程图作为教务管理系统设计的重要工具,能够清晰地展示系统的运作过程,帮助理解各个环节的逻辑关系。以下将详细阐述教务管理系统...

    MFC信息管理系统

    《MFC信息管理系统:深入解析与实践》 MFC(Microsoft Foundation Classes)是微软提供的一套C++类库,用于构建Windows应用程序。它基于面向对象的设计原则,为开发者提供了丰富的API,使得在Windows环境下开发图形...

    图书管理系统JAVA语言

    《图书管理系统JAVA语言》 图书管理系统是一个典型的信息化应用,它主要负责图书馆中图书的借阅、归还、查询、统计等一系列操作。在这个系统中,我们使用了强大的JAVA语言作为主要的开发工具,以及稳定的SQL Server...

    C# 图书管理系统图书管理系统图书管理系统图书管理系统图书管理系统图书管理系统

    《C# 图书管理系统》 图书管理系统是一种用于管理和组织图书馆藏书、读者信息以及借阅流程的软件系统。本系统采用C#编程语言进行开发,旨在提供高效、便捷的图书管理解决方案。C#,作为微软.NET框架的主要编程语言...

    家庭财务管理系统

    【家庭财务管理系统】是一款专为个人和家庭设计的软件,旨在帮助用户全面管理日常收支,实现财务状况的清晰掌握和有效规划。系统采用先进的开发技术,如Java,以确保稳定性和兼容性,使得用户能够在多种操作系统环境...

    c++学生管理系统 c++学生管理系统

    综上所述,C++学生管理系统涉及的知识点广泛,涵盖面向对象编程、数据结构与算法、文件操作、用户界面设计、异常处理、测试调试以及代码优化等多个方面。掌握这些知识点,不仅能帮助我们开发出高效、稳定的学生管理...

    学生管理系统软件测试报告

    随着信息技术的迅猛发展,学生管理系统作为教育信息化的重要组成部分,其稳定性与可靠性对学校管理工作的顺利进行具有举足轻重的作用。因此,通过科学的软件测试来确保学生管理系统的质量,是软件投入正式运行前不可...

    电信资费管理系统

    在电信资费管理系统中,Java提供了一套严谨的结构来设计和实现业务逻辑,包括类、对象、接口和异常处理等核心概念。 1. **面向对象编程**:系统中的每个功能模块,如用户管理、套餐定义、计费规则等,都可以抽象为...

    学生信息管理系统c++

    总的来说,C++实现的学生信息管理系统综合运用了面向对象编程、文件操作、数据结构、异常处理等多方面知识,体现了C++在实际项目中的强大能力。通过学习和理解这个系统,开发者不仅可以提升C++编程技能,还能对信息...

    网吧管理系统实现代码

    【网吧管理系统实现代码】是一个基于Java编程语言开发的软件项目,其主要目的是为了高效地管理和运营网吧业务。这个系统利用了MySQL数据库来存储和管理大量的用户数据,确保了信息的安全性和稳定性。以下是对该系统...

    酒店管理系统-完整源码

    酒店管理系统是一种基于计算机技术的信息化解决方案,用于提升酒店的运营效率和服务质量。它涵盖了酒店日常运营的各个环节,包括预订管理、入住登记、客房状态管理、账单计算、会员管理、餐饮服务、会议活动安排等。...

    学生管理系统(控制台)JAVA

    《学生管理系统(控制台)JAVA》 在编程领域,学生管理系统是一种常见的项目,它用于模拟学校对学生信息的管理。这个项目通常由初学者用来练习面向对象编程、数据库操作以及命令行界面的交互设计。本系统是用Java...

Global site tag (gtag.js) - Google Analytics