论坛首页 Java企业应用论坛

为什么 Java 中要使用 Checked Exceptions

浏览 192492 次
该帖已经被评为精华帖
作者 正文
   发表时间:2005-05-31  
引用
但是我也不同意都使用exception机制,这样做与使用返回值相比,仅仅是多了一些信息,在程序结构上仍然是分支处理,就象老庄说的,不过是if变成了try,


并非仅仅如此。异常可以让你只在你关心的地方处理错误,不关心的地方,直接声明throws了事。而if则必须在返回后立即处理,需要跳出循环或者多层函数调用的时候代码繁琐。

而且,异常有自己的类层次,可以让用户在任意抽象的层次处理,比如用户可以直接处理Exception,或者LoginException,也可以具体到AuthenticationFailedException这些具体错误的子类。



引用
而且这样还有严重的性能问题(即便不考虑有人恶意DOS,在一般情况下,登录信息输入的错误也是很常见的现象)。

严重?怎么个严重法?在一个
browser --> web server --> app server --> db server
-->app server --> web server --> browser
的roundtrip中,app server上的一个异常是瓶颈吗?要是这样,这网络工程师和dba肯定是天才了。
select ...的速度和一个异常哪个慢?

引用
我的作法是──使用多态:对于login代码段,返回值是一个User对象,如果登录失败,则返回一个缓存的anonymous 的User对象,如果用户被锁定,就返回一个被锁定的User对象,调用方只要使用这个User对象的getMainPage()即可(这是一个简化的作法,具体还要进一步修改)。

1。你这样是假设所有的错误都能抽象出一个相同的类型来,都用一个getMainPage()就可以涵盖。这个假设大胆了些。多数情况下,错误种类是可以扩展的,而每个错误所携带的信息也可以随着要求的细化越来越多,而且没什么·共同规律可循。很难用一些虚函数涵盖。
2。getMainPage()是表示层的逻辑,login()则是业务层的逻辑。你让业务层依赖表示层。那么万一我要更换表示层呢?变成getMainScript()?变成getMainSwingClass()?
循环依赖,万恶之源。
这也是盲目反对异常带来的设计上的恶果之一。典型的反面教材。
其实,要是真想用多态,也得用一个visitor pattern。如此,就不需要依赖表示层,也不需要抽象出一个universal的接口来覆盖所有错误。
只不过,visitor的理解和设计都比异常绕,而且visitor在增加类型的时候要改动客户代码,也是很讨厌的。
总而言之,没有一种方法比用异常更简洁清楚。
0 请登录后投票
   发表时间:2005-05-31  
本来我是没怎么考虑过这个问题的..........
刚看到robbin的code也觉得多此一举
下面又有一人不停的说 要去看 E什么什么JAVA (英文不好 没记住) 就去看了一下
那里面关于异常的那部分 的确说了 不要随便使用异常控制流程 不要随便制作自己的异常
可是他给的例子就是一个类似于LogoInfo的异常控制流程的code 估计是在作者的脑袋里 这个并不违反他说的那几条 恩恩...........看来想法要变一变了..........
0 请登录后投票
   发表时间:2005-05-31  
ajoo 写道
并非仅仅如此。异常可以让你只在你关心的地方处理错误,不关心的地方,直接声明throws了事。而if则必须在返回后立即处理,需要跳出循环或者多层函数调用的时候代码繁琐。
而且,异常有自己的类层次,可以让用户在任意抽象的层次处理,比如用户可以直接处理Exception,或者LoginException,也可以具体到AuthenticationFailedException这些具体错误的子类。
你说的对,这是我考虑不全面的地方。不过补充一句闲话,异常的类层次容易诱导“类爆炸”,所以一个项目中的异常类还需要精心组织,原则上尽量重用jdk提供的,自己仅设计与项目相关的上层异常。

ajoo 写道
引用
而且这样还有严重的性能问题(即便不考虑有人恶意DOS,在一般情况下,登录信息输入的错误也是很常见的现象)。

严重?怎么个严重法?在一个
browser --> web server --> app server --> db server
-->app server --> web server --> browser
的roundtrip中,app server上的一个异常是瓶颈吗?要是这样,这网络工程师和dba肯定是天才了。
select ...的速度和一个异常哪个慢?
数据库访问有多级cache,异常没有,甚至在一般的jvm中都不对异常进行优化──因为JVM认为这是很少见的情形。

ajoo 写道
引用
我的作法是──使用多态:对于login代码段,返回值是一个User对象,如果登录失败,则返回一个缓存的anonymous 的User对象,如果用户被锁定,就返回一个被锁定的User对象,调用方只要使用这个User对象的getMainPage()即可(这是一个简化的作法,具体还要进一步修改)。

2。getMainPage()是表示层的逻辑,login()则是业务层的逻辑。你让业务层依赖表示层。那么万一我要更换表示层呢?变成getMainScript()?变成getMainSwingClass()?

这只是举个例子,将问题简化,实际上我的目的就是使用一个一致的接口
ajoo 写道
1。你这样是假设所有的错误都能抽象出一个相同的类型来,都用一个getMainPage()就可以涵盖。这个假设大胆了些。多数情况下,错误种类是可以扩展的,而每个错误所携带的信息也可以随着要求的细化越来越多,而且没什么·共同规律可循。很难用一些虚函数涵盖。

这一点我也没想清楚,真实情况下,怎么处理异常依赖于对问题域的理解,也许我会返回一个command吧。

ddandyy 写道
本来我是没怎么考虑过这个问题的..........
刚看到robbin的code也觉得多此一举
下面又有一人不停的说 要去看 E什么什么JAVA (英文不好 没记住) 就去看了一下
那里面关于异常的那部分 的确说了 不要随便使用异常控制流程 不要随便制作自己的异常
可是他给的例子就是一个类似于LogoInfo的异常控制流程的code 估计是在作者的脑袋里 这个并不违反他说的那几条 恩恩...........看来想法要变一变了..........

我怎么没有找到那个例子阿,rpwt?
0 请登录后投票
   发表时间:2005-05-31  
checked exception,会用就用,当你需要的时候,它在身边,在你还没有体会到的时候,何必去强求,体会过unchecked exception的无力,自然会了解。

那种说绝对不能使用checked exception做分支处理流程(注意“绝对”一词),我真晕,程序里面只要是异常被throw,不就是分支??!!!!
那么叫什么?

如果把一只狗的尾巴叫做腿,那么一只狗有几条腿?(只讨论正常情况)


还是4条腿
0 请登录后投票
   发表时间:2005-05-31  
引用
不过补充一句闲话,异常的类层次容易诱导“类爆炸”,所以一个项目中的异常类还需要精心组织


吃饭也会被噎死,不能因为这个就不吃饭吧。
代码本来就是应该被精心组织的,何况异常

引用
数据库访问有多级cache,异常没有,甚至在一般的jvm中都不对异常进行优化──因为JVM认为这是很少见的情形。


还真很少听说,因为异常成乐瓶颈,
汽车和飞机哪个快?为什么你不是每天做飞机上下班?
理论上虽然说效率有问题,但是要看参照物(坐标系)的,
太阳是离地球最近的恒星,真的很近哦,
你说近不?!
0 请登录后投票
   发表时间:2005-05-31  
异常类层次设计的不好带来的结果就是非常糟糕,例如JTA的异常类层次,例如EJB的异常类层次,但是也有设计的很好的,例如Spring DataAccessException类层次结构。

用设计糟糕的异常类层次来否定异常这个事物,是极度缺乏说服力的,就好像有人用菜刀砍了人,你不能否定这把菜刀一样。

这个帖子这么长了,该讨论的问题都讨论清楚了,总结也总结过n遍了,所以我早就没有兴趣再跟帖了。

实际上,这个讨论中隐含两个不断纠缠的话题:

1、checked ,还是unchecked异常?
2、用自定义的方法调用返回code,还是用异常来表达不期望各种的事件流

经过这么长的讨论,我认为结论已经非常清楚:

1、应该适用unchecked异常,也就是runtimeexception,这样可以让无法处理异常的应用代码简单忽略它,让更上层次的代码来处理

2、应该适用异常来表达不期望的各种事件流

事实上,你们去看一下现在Spring,Hibernate3都已经采用这种方式,特别是Spring的DataAccessException异常层次设计,是一个很好的例子。即使用RuntimeException来表达不期望的各种事件流。
1 请登录后投票
   发表时间:2005-06-01  
I favor RuntimeException too.

But, sometimes, I do miss checked exception when I forget to catch an exception that's supposed to be handled, or forget to "throws" a runtime exception (for documentation reason)


trade-off.



0 请登录后投票
   发表时间:2005-06-02  
要从vm的角度看待问题.
0 请登录后投票
   发表时间:2005-06-02  
没想到基础问题也能成为大肠贴!

仔细看看jdk/ejb里面对异常的设计/使用,就是robbin的那种方式。

对于通过方法返回值来判断各种异常流程的方式,其实是过程化编程里面的典型风格。

另外关于效率,请大家仔细想想计算机程序最近十几、二十年的发展,是不是遵循着这样一个方向:不断地向高层抽象(接近人类的思维方式),不断地远离底层(机器的思维方式)。

越面向底层的程序,执行效率越高,但是大量普通人/普通公司越以掌握,难以在有限的时间内生产出大规模的系统(IBM之类的公司除外)。你可以用汇编写驱动,写某些核心程序,但是你能完全用它来写一个基于internet的企业级分布式应用么?退一步说即使本帖子读者中有天才牛人可以写出来,但是估计你的公司也不会让你这么干吧。

不断向高层抽象的目的,是使的普通人/公司能够进行相对快速的更大规模编程。但是随之而来的必然是损失一部分程序执行效率。

我想只要是在当前时代的硬件水平下,不引起无法容忍的低效就不应该过分从底层细节上追究效率问题,更多的应该是站在程序整体框架的角度上考虑它。
0 请登录后投票
   发表时间:2005-08-07  
http://www.javaworld.com/javaworld/jw-07-2005/jw-0711-exception.html
0 请登录后投票
论坛首页 Java企业应用版

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