该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间: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在增加类型的时候要改动客户代码,也是很讨厌的。 总而言之,没有一种方法比用异常更简洁清楚。 |
|
返回顶楼 | |
发表时间:2005-05-31
本来我是没怎么考虑过这个问题的..........
刚看到robbin的code也觉得多此一举 下面又有一人不停的说 要去看 E什么什么JAVA (英文不好 没记住) 就去看了一下 那里面关于异常的那部分 的确说了 不要随便使用异常控制流程 不要随便制作自己的异常 可是他给的例子就是一个类似于LogoInfo的异常控制流程的code 估计是在作者的脑袋里 这个并不违反他说的那几条 恩恩...........看来想法要变一变了.......... |
|
返回顶楼 | |
发表时间:2005-05-31
ajoo 写道 并非仅仅如此。异常可以让你只在你关心的地方处理错误,不关心的地方,直接声明throws了事。而if则必须在返回后立即处理,需要跳出循环或者多层函数调用的时候代码繁琐。
你说的对,这是我考虑不全面的地方。不过补充一句闲话,异常的类层次容易诱导“类爆炸”,所以一个项目中的异常类还需要精心组织,原则上尽量重用jdk提供的,自己仅设计与项目相关的上层异常。
而且,异常有自己的类层次,可以让用户在任意抽象的层次处理,比如用户可以直接处理Exception,或者LoginException,也可以具体到AuthenticationFailedException这些具体错误的子类。 ajoo 写道 引用 而且这样还有严重的性能问题(即便不考虑有人恶意DOS,在一般情况下,登录信息输入的错误也是很常见的现象)。
严重?怎么个严重法?在一个 browser --> web server --> app server --> db server -->app server --> web server --> browser 的roundtrip中,app server上的一个异常是瓶颈吗?要是这样,这网络工程师和dba肯定是天才了。 select ...的速度和一个异常哪个慢? 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? |
|
返回顶楼 | |
发表时间:2005-05-31
checked exception,会用就用,当你需要的时候,它在身边,在你还没有体会到的时候,何必去强求,体会过unchecked exception的无力,自然会了解。
那种说绝对不能使用checked exception做分支处理流程(注意“绝对”一词),我真晕,程序里面只要是异常被throw,不就是分支??!!!! 那么叫什么? 如果把一只狗的尾巴叫做腿,那么一只狗有几条腿?(只讨论正常情况) 还是4条腿 |
|
返回顶楼 | |
发表时间:2005-05-31
引用 不过补充一句闲话,异常的类层次容易诱导“类爆炸”,所以一个项目中的异常类还需要精心组织
吃饭也会被噎死,不能因为这个就不吃饭吧。 代码本来就是应该被精心组织的,何况异常 引用 数据库访问有多级cache,异常没有,甚至在一般的jvm中都不对异常进行优化──因为JVM认为这是很少见的情形。
还真很少听说,因为异常成乐瓶颈, 汽车和飞机哪个快?为什么你不是每天做飞机上下班? 理论上虽然说效率有问题,但是要看参照物(坐标系)的, 太阳是离地球最近的恒星,真的很近哦, 你说近不?! |
|
返回顶楼 | |
发表时间:2005-05-31
异常类层次设计的不好带来的结果就是非常糟糕,例如JTA的异常类层次,例如EJB的异常类层次,但是也有设计的很好的,例如Spring DataAccessException类层次结构。
用设计糟糕的异常类层次来否定异常这个事物,是极度缺乏说服力的,就好像有人用菜刀砍了人,你不能否定这把菜刀一样。 这个帖子这么长了,该讨论的问题都讨论清楚了,总结也总结过n遍了,所以我早就没有兴趣再跟帖了。 实际上,这个讨论中隐含两个不断纠缠的话题: 1、checked ,还是unchecked异常? 2、用自定义的方法调用返回code,还是用异常来表达不期望各种的事件流 经过这么长的讨论,我认为结论已经非常清楚: 1、应该适用unchecked异常,也就是runtimeexception,这样可以让无法处理异常的应用代码简单忽略它,让更上层次的代码来处理 2、应该适用异常来表达不期望的各种事件流 事实上,你们去看一下现在Spring,Hibernate3都已经采用这种方式,特别是Spring的DataAccessException异常层次设计,是一个很好的例子。即使用RuntimeException来表达不期望的各种事件流。 |
|
返回顶楼 | |
发表时间: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. |
|
返回顶楼 | |
发表时间:2005-06-02
要从vm的角度看待问题.
|
|
返回顶楼 | |
发表时间:2005-06-02
没想到基础问题也能成为大肠贴!
仔细看看jdk/ejb里面对异常的设计/使用,就是robbin的那种方式。 对于通过方法返回值来判断各种异常流程的方式,其实是过程化编程里面的典型风格。 另外关于效率,请大家仔细想想计算机程序最近十几、二十年的发展,是不是遵循着这样一个方向:不断地向高层抽象(接近人类的思维方式),不断地远离底层(机器的思维方式)。 越面向底层的程序,执行效率越高,但是大量普通人/普通公司越以掌握,难以在有限的时间内生产出大规模的系统(IBM之类的公司除外)。你可以用汇编写驱动,写某些核心程序,但是你能完全用它来写一个基于internet的企业级分布式应用么?退一步说即使本帖子读者中有天才牛人可以写出来,但是估计你的公司也不会让你这么干吧。 不断向高层抽象的目的,是使的普通人/公司能够进行相对快速的更大规模编程。但是随之而来的必然是损失一部分程序执行效率。 我想只要是在当前时代的硬件水平下,不引起无法容忍的低效就不应该过分从底层细节上追究效率问题,更多的应该是站在程序整体框架的角度上考虑它。 |
|
返回顶楼 | |
发表时间:2005-08-07
http://www.javaworld.com/javaworld/jw-07-2005/jw-0711-exception.html
|
|
返回顶楼 | |