论坛首页 Java企业应用论坛

JAVA异常设计原则

浏览 31088 次
精华帖 (7) :: 良好帖 (6) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2011-01-04  
计算机软件异常

  Exception 机制
  为什么要自定义自己的Exception ,Java Exception机制与传统的C语言的异常处理机制有什么不同,这种Exception机制的意义在什么地方?接下来咱就来和你一起探讨Exception 的优缺点。
  早期的C语言的异常处理机制,通常是我们人为的对返回结果加一些标志来进行判定,比如发生错误返回什么标志,正常情况下我们又是返回什么标记,而这些都不是语言本身所赋予我们的,而对于C语言这种机制又有什么问题哩?为什么新一代的语言 Java Ruby C# 等都用Exception机制而不是维持C语言的老样子?这些都是我们需要思考的问题。
  C语言的异常处理机制全是我们人为的定义,这样就会造成业务逻辑的主线受到异常处理的牵制,或者说是我们难免会将注意力转移,并且造成业务逻辑与异常处理之间有很大程度上的缠绕。
  理论上异常处理划分为两个模型(中止模型与继续模型),但实际使用方面我们对中止模型用的比较多,这个模型比较实用,而继续模型则不是那么的应用普遍,多少是耦合的过于紧密。
  中止模型 :
  假设错误非常严重,已至你无法在回到错误发生的地方,也就是说,这段程序经过判断认为,他已经没有办法挽回,于是就抛出异常,希望这个异常不要在回来,这也是Java 当前所采用的模式。
  继续模型:
  这种模型的主旨是恢复当前的运行环境,然后希望能够重新回到错误的发生地,并希望第二次的尝试能够获得成功,这种模型通常为操作系统所应用。
  异常的常见例子有内存分配不足、数组下标越界、运算溢出或除数为零。
  使用异常的原因(参考csdn):取代返回值表示错误状态、使程序可以继续运行、发生异常时记录错误信息……
  C++异常处理析构类对象、已调用的函数退栈……
  Java中的异常
  异常:程序在运行过程中发生由于硬件设备问 题、软件设计错误等导致的程序异常事件
  异常本身是一个对象,产生异常就是产生了一个异常对象。
  通过try…catch语句进行捕获异常。
  异常都是从类Throwable派生出来。

出处:http://baike.baidu.com/view/209658.htm
0 请登录后投票
   发表时间:2011-01-05  
badqiu 写道
luckaway 写道
badqiu 写道

没搞明白你,难道你 Checked Exception带的信息就比我 UncheckedException信息丰富? 我是说异常体系根本就不需要Checked Exception存在,然后你所要完成的功能全部由 UncheckedException完成。Checked,Unchecked只有在调用处强制处理异常的区别,功能完全是一样的。

举个例子。

我们的servlet要调用你的一个 service方法.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
    // 现在我只能抛出 ServletException,IOException,抛不出去SomeCheckedException
    try {
        someService.execute();
    }catch(SomeCheckedException e) {
        // 你竟然要求我立即在这里 处理异常,连给我通过框架统一处理异常的机会都没有,不SB么?
        // 所以,因为CheckdException,我在这里只能 log一次,或者是 throw new RuntimeException(e);
    }
}



如果仅仅是记录错误日志或者throw new RuntimeException(e),是没必用Checked Exception。JDK的Checked Exception,如:SqlException、UnsupportedEncodingException ,我们都是简单的封装成runtime Exception,也不会增加额外的信息,这种场景下,确实不应该是Checked Exception。


Unchecked Exception和Checked Exception都能携带信息,Unchecked Exception里携带的信息只会给日志记录用。
Checked Exception携带信息更多的作用是给用户看的,甚至有可能都不记录日志了。

public String execute() {
	try {
		userService.transferCoin(coin);
	} catch (CoinNotEnoughException e) {
		context.put("errorMessage", "你目前的金币是" + e.getTotalCoin() + ",无法转账" + e.getForTransferCoin());
	}
	return SUCCESS;
}



如你自己的demo,你的调用方一定需要强制处理该异常了。 已经没有办法使用框架来处理异常。

你的Checked Exception只是你自己一厢情愿的认为按你现在的方式处理。
难道其它语言没有 Checked Exception就不用活了。 硬按你这种规则区分。

SqlException,UnsupportedEncodingException, DateFormat ParseException 都是JDK败笔,已经懒得说了。


我一直所说使用Checked Exception最主要的缺点: 接口污染,强制调用者立即处理。
所以不用跟我说 Exception转换为message的程序了. 因为要转换为消息的时候,我也直接处理CoinNotEnoughException 这个RuntimeException. 而不是Checked Exception


是有弊端的,异常太多,代码就会比较丑陋! 强制处理,程序会更健壮点,如果是RuntimeExcetion可能会漏掉。

我一般定义接口的时候,都先跟同事先交流,是如何控制。 避免定义了Checked Exception,而不使用的局面。

0 请登录后投票
   发表时间:2011-01-05  
引用

都需要提供丰富的信息。如:数据库访问异常,需要提供查询sql语句等;HTTP接口调用异常,需要给出访问的URL和参数列表(如果是post请求,参数列表不提供也可以,取决于维护人员或者开发人员拿到参数列表会如何去使用)。


写的不错,提供信息非常重要,对查找错误的原因有很多的帮助。
大部分开发人员,只会创建没有意义的异常类,除了有个性名字外,就没有其他额外方法了。

设计异常类要跟普通类要一样,要有自己的属性和方法

0 请登录后投票
   发表时间:2011-01-05  
C. 捕获顶层的异常—Exception

没明白你的意思,你是说不能用Exception 一次性catch代码里抛出的异常吗?
0 请登录后投票
   发表时间:2011-01-05   最后修改:2011-01-05
呵呵,我感觉是这样的,其实出现异常的时候,一般来说有2种视角,一种是开发者的视角,一种是用户的视角。对于开发者来说,出现异常时,要求记录log,异常信息越详细越好。对于用户来说,他们是不关心内部细节,所以只要给他们容易理解的语言提示就好。
所以一般来说,出现底层模块出现异常时,我们会先在异常现场用log4j等工具记录异常的堆栈信息,然后包装之重新向上层模块抛出,上层一般会在一个比较适合的层次集中处理底层抛出的异常,并将易理解的错误信息报告给用户。


至于unchecked 和 checked 异常,我感觉其实是这样的:

checked异常使用场景:就是我一个操作的结果并不是确定的,一般是可以成功的,但是也有一定几率失败,而且这个失败不是你这层可控的,比如说读写文件,网络io,访问数据库,这个时候,你就要声明checked 异常了。也就是提示你的接口的使用者注意,你调用我是有不可预知的错误情景,你一定要主动防备。

unchecked异常是运行时异常,就是说这个异常出现是跟你当前执行模块的上下文相关的,其实多半是程序bug,或者参数超出临界值等原因造成的,出现这种情况是谁都没折的,你也是无法防备的。
0 请登录后投票
   发表时间:2011-01-05  
gdpglc 写道
C. 捕获顶层的异常—Exception

没明白你的意思,你是说不能用Exception 一次性catch代码里抛出的异常吗?

是的,IllegalArgumentException或者NullPointException等RuntimeException就要保持原味的,但是Action要捕获所有的RuntimeException异常!
0 请登录后投票
   发表时间:2011-01-05   最后修改:2011-01-05
luckaway 写道
gdpglc 写道
C. 捕获顶层的异常—Exception

没明白你的意思,你是说不能用Exception 一次性catch代码里抛出的异常吗?

是的,IllegalArgumentException或者NullPointException等RuntimeException就要保持原味的,但是Action要捕获所有的RuntimeException异常!

我理解,你的意思是,没必要catch这些运行时异常吧?
如果Dao有若干个checked exception,是不是用Exception catch就可以了?
更具体点,我的意思是,比如先做一个文件操作然后调Dao,这时总体上我用一个Exception作catch有问题吗?
0 请登录后投票
   发表时间:2011-01-05  
gdpglc 写道
luckaway 写道
gdpglc 写道
C. 捕获顶层的异常—Exception

没明白你的意思,你是说不能用Exception 一次性catch代码里抛出的异常吗?

是的,IllegalArgumentException或者NullPointException等RuntimeException就要保持原味的,但是Action要捕获所有的RuntimeException异常!

我理解,你的意思是,没必要catch这些运行时异常吧?
如果Dao有若干个checked exception,是不是用Exception catch就可以了?
更具体点,我的意思是,比如先做一个文件操作先后调Dao,这时总体上我用一个Exception作catch有问题吗?


Dao的Checked Exception的不应该抛到Service,这些异常跟业务是没关系的,比如是文件访问出错,在Dao里做如下处理。
	public void readFile(String fileName) {
		File file = new File(fileName);
		try {
			FileInputStream fileInputStream = new FileInputStream(file);
		} catch (IOException e) {
			throw new FileResourceAccessException("IOException while operate " + fileName, e);
		}
	}



有时候我们可能用异常来实现某个业务需求,比如需求测试某条sql是否可用,而现有的API没直接提供检测的方法。
那实现方法如下:

XXXDao.java

public boolean isSqlValid(String sql){
   try{
      //do sql query          
      return true;
    }catch(SQlException e){
     return false;
    }
}


至少我还没想到那种情景下Dao的Checked Exception需要抛到Service层。



0 请登录后投票
   发表时间:2011-01-05   最后修改:2011-01-05
luckaway 写道
gdpglc 写道
luckaway 写道
gdpglc 写道
C. 捕获顶层的异常—Exception

没明白你的意思,你是说不能用Exception 一次性catch代码里抛出的异常吗?

是的,IllegalArgumentException或者NullPointException等RuntimeException就要保持原味的,但是Action要捕获所有的RuntimeException异常!

我理解,你的意思是,没必要catch这些运行时异常吧?
如果Dao有若干个checked exception,是不是用Exception catch就可以了?
更具体点,我的意思是,比如先做一个文件操作先后调Dao,这时总体上我用一个Exception作catch有问题吗?


Dao的Checked Exception的不应该抛到Service,这些异常跟业务是没关系的,比如是文件访问出错,在Dao里做如下处理。
	public void readFile(String fileName) {
		File file = new File(fileName);
		try {
			FileInputStream fileInputStream = new FileInputStream(file);
		} catch (IOException e) {
			throw new FileResourceAccessException("IOException while operate " + fileName, e);
		}
	}



有时候我们可能用异常来实现某个业务需求,比如需求测试某条sql是否可用,而现有的API没直接提供检测的方法。
那实现方法如下:

XXXDao.java

public boolean isSqlValid(String sql){
   try{
      //do sql query          
      return true;
    }catch(SQlException e){
     return false;
    }
}


至少我还没想到那种情景下Dao的Checked Exception需要抛到Service层。





dao 可以不抛checked exception. 但是,出现下面的情况,是不是需要在service里边处理异常呢?

比如某个Service方法写成这样了呢:

1. file logic
2. dao invoking logic

0 请登录后投票
   发表时间:2011-01-05  
gdpglc 写道

dao 可以不抛checked exception. 但是,出现下面的情况,是不是需要在service里边处理异常呢?

比如某个Service方法写成这样了呢:

1. file logic
2. dao invoking logic



不是很明白你的意思,file logic不应该直接在Service处理,操作File都应该放在Dao里处理
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics