`
bubusy
  • 浏览: 2062 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

关于java异常使用的一些思考

阅读更多
一直被异常问题困扰。写一下自己的一些看法。很多地方牵扯到一些java开发常用的框架。

spring框架将所有的sql或者Hibernate异常转换成了自己的unchecked异常(DataAccessException),这种异常既可以捕捉也可以不捕捉。这样就有了一个问题,在我们的代码中捕捉这些异常呢,还是不捕捉。我认为应该捕捉,因为如果不捕捉,那么就忽略了程序发生的错误,并且如果我们不捕捉,那么那些unchecked异常最终也会被java虚拟机捕捉,到时候将导致程序不能运行。由此看来,要捕捉,可是要怎么捕捉,在哪里捕捉呢?我想这个问题才是比较关键的问题,并且答案不是唯一的。首先,这些异常是来自jdbc的sql异常,或者来自Hibernate的异常。可以简单的把它们看做是由数据源产生的异常。这类异常是很难处理的。

我们的程序一般都是分层设计,自上而下为:顶层(笼统的代表处理页面的层,该层调用service层)、service层、dao层。dao层负责跟最底层的数据源(jdbc或者Hibernate)交互。那来自于数据源的异常我们应该在哪一层捕捉并且处理(处理可能指直接处理,也可能指转换成其它异常类型)?这是个比较难以权衡的问题。如果我们在比较低的层次(比如dao层)进行捕捉并处理,那么怎么处理,处理的结果又如何反应到应用程序当中?

以一个简单的例子来看,用户注册:

先来看用户注册的流程:
用户填写用户信息->用户提交信息->服务端(假设是一个action)接收用户信息->服务端调用service->service调用dao->dao使用数据源完成用户信息持久化。这是一个理想的流程,但是在这个流程中可能会发生一些分支,比如用户名已经被占用,密码不合规范,用户信息不完整等。为了当发生这些分支时程序仍然能够正常处理,我们可以在用户提交信息和服务端接收信息直接加一个用户信息验证的过程。该过程可以处理密码不合规范、用户习信息不完整等问题。可以将该过程看做一个静态验证过程。
对于用户名被占用的问题,可能有以下两种实现:

1、服务端接收信息后先service检查用户名是否已经存在,比如service上有个返回布尔型的isUsrNameExist()方法。若存在,action做相应处理,最终反映在返回页面上。
2、服务端接收信息后直接调用用service上的方法进行注册,比如service上有一个返回void的reg(User u)方法,该方法将抛出UserNameExistsException异常。action调用service的reg方法时要捕捉并处理该异常,并根据异常反映相应结果到页面上。

我们可把上面的情况看做一个注册用例的逻辑上可能发生的情况,称为可预期异常。但是还有一种因为数据库原因或程序代码原因产生的异常。这类异常不是可预期的,一旦产生,很难处理。spring里的DataAccessException异常就属于这类异常。

难处理并不代表可以不处理,虽然java的机制并没有强制要求我们处理这类异常。我认为应该让这类异常自动向上抛出,直到在某一个层对它们进行统一处理。对于webapp,那么如果我们的代码没有处理这类异常,那么servlet容器(比如Tomcat)最终会处理。那如果我们的代码在运行时抛出了这类异常,我们是不是就不用管它们,完全交给Tomcat来处理呢?理论上可以,但是Tomcat的异常处理页面不够友好。不可取。Tomcat允许我们自定义错误处理界面,这样我们就可以提供一个相对友好的异常界面。但是我们仍然不能直接将异常叫个Tomcat来处理,因为程序中抛出的异常信息不友好,由于跨越了好几个层,原始异常中携带的信息对我们定位异常或者根据异常做相应处理提供的帮助不大。因此我们可以在每一个层对unchecked异常进行包装,将其转换成自定义的异常类型以包含更多信息。

综上,我们自定义一个异常体系:
受查异常基类:AppException extend Exception
不受查异常:AppRunTimeException extend RunTimeException
受查异常参与业务逻辑,反映可预期的业务逻辑分支和用例。主要出现在service层,供service层或者action层捕捉并处理。不受查异常不参与业务逻辑,可在任意层抛出,根据情况捕捉,并在包装后继续向上抛出,最终由Tomcat自定义的错误界面统一处理。

异常还是返回值?
在用例和业务逻辑中,出现可预期的分支是很常见的。如何处理分支呢?

使用返回值:这应该是比较传统的做法。比如我们有login,reg等业务方法,可以给方法一个返回值,然后在action里或者service里根据调用方法得到的返回值做判断。这种做法易于理解,更接近于过程化得思维。

使用受查异常:客户代码调用service提供的方法,service方法执行过程中抛出异常(受查异常,这样做是为了强制客户代码处理流程分支),客户代码对捕捉到的异常进行处理,转而执行相应分支。这种做法比较容易用面向对象的思维来理解,但是必将带来庞大的业务相关的自定义异常体系。

到底两者孰优孰劣?
我认为对于简单的业务逻辑少的系统,使用前者更好。理由是:不用去维护一个异常体系模型。由于系统简单,使用返回值的方法就足以轻松应对多数需求。对于业务逻辑复杂庞大的系统,使用后者更好。理由是:业务逻辑复制的系统,其可能的分支情况将更多,通过业务方法返回值的方式来应对这样一种情况显得比较吃力。而如果使用一个异常体系,由于异常体系本身具有一定的含义,程序能更好得从程序设计文档(比如UML设计)过度而来,更易于理解和维护。具体怎么用,还是要根据系统的具体情况,我觉得甚至都可以混合使用。
2
0
分享到:
评论

相关推荐

    Java异常处理和最佳实践(含案例分析).pdf

    Java异常处理并不是一个简单的事情,不仅初学者很难理解,甚至一些有经验的开发者也需要花费很多时间来思考如何处理异常。阿里巴巴Java开发规范中有15条关于异常处理的说明,但是这些说明告诉了我们应该怎么做,却...

    java思考

    如果这是一个文本文件,那么它可能包含了博主对于Java语言的深入见解,包括但不限于类和对象、封装、继承、多态等面向对象特性,也可能是关于异常处理、集合框架、IO流、线程并发、反射、泛型、注解等方面的讨论。...

    java基础知识思考题+答案(个人整理)

    ### Java基础知识思考题详解 #### 1. 缩写JDK的含义是什么? JDK,全称Java Development Kit,即Java开发工具包。它是Java软件开发的基础,包含了编写、编译和运行Java程序所需的所有工具。JDK不仅包括Java编译器...

    java基础巩固,思考 java-se java基础巩固,思考,从底层到精通 测试一个

    4. **异常处理**:学习如何使用try-catch-finally语句块进行异常处理,以及标准的Java异常类层次结构。 5. **集合框架**:掌握ArrayList、LinkedList、HashSet、HashMap等集合类的使用,理解它们之间的区别以及何时...

    关于java中对象属性值的校验的思考

    在Java中,可以使用注解(Annotations)配合校验框架来简化这一过程。Hibernate Validator是一个流行的Java Bean校验框架,它支持JSR-303和JSR-349标准。通过在属性上定义如`@NotNull`、`@Min`、`@Max`等注解,可以...

    java 方法的流程控制与异常处理

    - **掌握Java异常处理的方法**:学会使用`try-catch-finally`语句块进行异常的捕获与处理,以及如何自定义异常类。 - **理解方法重载的特点,并会熟练构造重载的方法**:通过编写多个版本的函数,掌握函数重载的规则...

    Java面向对象程序设计 实验四 异常处理

    Java面向对象程序设计实验四 异常处理 Java面向对象程序设计实验四的主要目的是掌握异常处理的技术,了解自定义异常类与异常跟踪栈的概念。在这个实验中,我们将学习如何捕获并处理异常,并通过编写程序来验证...

    Java程序设计教程,电子教案,实例源程序,思考练习参考答案

    3. **异常处理**:Java提供了异常处理机制,通过try-catch-finally语句块来捕获和处理运行时错误,保证程序的健壮性。 4. **函数与方法**:函数是代码的复用单元,方法是类中的函数。理解参数传递、方法重载和...

    [探秘Java:如何像计算机科学家一样思考].(唐尼).张平.扫描版.pdf

    《探秘Java:如何像计算机科学家一样思考》这本书由唐尼撰写,张平翻译,旨在帮助读者以计算机科学家的视角理解和掌握Java编程语言。通过深入阅读这本书,我们可以挖掘出一系列重要的Java编程和计算机科学思维的知识...

    java面向对象编程课后思考题答案

    以上是Java面向对象编程的一些基本概念,通过解决孙卫琴女士教程中的课后思考题,学习者可以更好地理解和应用这些知识。解答集"answer"应详细阐述了这些问题的解题思路和实现方法,对于深入学习和复习Java面向对象...

    Java复习---思考题

    Java 复习资料中的思考题涵盖了Java的基础知识,包括JDK的含义、Java跨平台技术、垃圾收集机制、J2SE、J2ME、J2EE的区别、包的作用、J2SE类库的主要包以及Java编程规范和程序结构。下面将详细解答这些知识点。 1. ...

    java大富翁_Java游戏_大富翁Java游戏_

    【描述】中的"java玉玺游戏好玩的很好玩的小虞兮西撒哈拉上线啦上线啦思考和"这部分似乎包含了一些拼写错误和不完整的句子,可能是在表达游戏的趣味性和新版本发布的信息。"玉玺游戏"可能是对"Java游戏"的一种形象...

    《Java面向对象编程》思考题及答案PDF

    8. **异常处理**:Java提供了异常处理机制,通过try-catch-finally语句块来捕获和处理运行时可能出现的错误,提高程序的健壮性。 9. **集合框架**:Java集合框架包括List、Set、Map等接口和ArrayList、HashSet、...

    java-大数据基础面试思考.pdf

    故障安全迭代器在迭代过程中不会抛出ConcurrentModificationException异常,它们使用的是集合的一个快照,因此在多线程环境下使用比较安全,不会抛出异常。不过,这种迭代器的缺点是无法保证遍历到最新的数据,因为...

    从Java菜鸟到专家的资料

    2. **Think In Java.chm**:这是经典的《深入思考Java》电子版,作者Bruce Eckel深入浅出地讲解了Java语言的核心概念,包括面向对象编程、集合框架、多线程、异常处理等内容,是Java初学者必读的书籍之一。...

    对Java的思考(Thinking in Java) Java入门 java与C++对比 深入浅出

    此外,本章还介绍了类的定义,包括字段和方法,以及构建Java程序的基本步骤,如命名规则、可见性和使用static关键字。 第3章"控制程序流程"详细阐述了Java中的控制结构,包括各种运算符的用法,如赋值、比较、逻辑...

    《java编程思想》_java编程思想_java编程思想_ThinkinginJava_mileefx_

    "Thinking in Java",直译为“思考Java”,鼓励读者不仅仅是学习语法,而是要理解Java的设计理念和背后的思考方式,从而提升编程能力。 Java编程思想的核心概念包括: 1. **面向对象编程**:Java是一种完全面向...

Global site tag (gtag.js) - Google Analytics