该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2003-12-23
Exception alway 是意外,不要把业务逻辑加到其中。
比如磁盘读写,数据库操作,网络联接,这些才是外部环境/基础组件引起的意外。 |
|
返回顶楼 | |
发表时间:2003-12-24
在Joshua Bloch的《Java高效编程指南》——异常那一节当中,对异常这个问题有过一个整体的描述。例如他总结的几条原则:
1、仅在不正常的情况下使用异常; 2、对可恢复的情况使用已检查异常,对程序错误使用运行时异常; 3、避免已检查异常的不必要使用; 4、使用标准的异常用法; …… 9、不要忽略异常。 其中在第一条原则中总结到(跟我们这个帖子谈到的问题一样): 像名字暗示的那样,异常应该仅仅被用在意外的情况下,永远不要把它们作为扑通控制流; 设计良好的API不应迫使客户使用异常作为正常的控制流。 那么我认为在实际的编程中,容易出现的大量问题就是: 1、方法体缺少pre-check; 2、方法申明抛出Exception,而不是更具体的Exception; 3、try-catch中只catch一个Exception,而没有细化(印度人在这点上比我们好多了)。 |
|
返回顶楼 | |
发表时间:2003-12-24
重新看了一遍大家的讨论,我又回顾了一下自己目前正在做的这个项目,像是又有了一些新的领悟,请指正:
我们这里的人大多是做应用的,而不是做组件、框架的,这两类开发需要的思路可能不太一样。 从做应用的角度看,我希望利用异常来管理显示在用户面前的错误提示,这样我就会将异常划分为两类,一类是可以显示给用户看的,或者说用户可以看的懂的,一类是给维护人员看的,就是通常说的系统错误,可以想象,让用户看到“空指针异常”是极不友好的行为。我们的项目中有一个专门显示错误的页面,它要么显示有具体业务含义的错误,要么就显示“系统错误”(然后维护人员可以从log中查找错误)。而前一类错误里面,每种错误总有一个不同的异常类和它对应,或者说,业务逻辑方法向表示逻辑抛出的异常,表示逻辑不需要分别处理(不要显示错误的除外),一律交给错误页面(其实是ErrorPageUIAction,我们用Struts),错误页面看是什么异常就显示什么错误提示,这里错误页面需要一个XML,XML里面定义了异常和错误提示的对应关系,当然XML里面只能有用户异常,不在XML里面的异常错误页面就会显示“系统错误”。业务逻辑事先将用户异常登记到XML中,这样错误信息还可以单独、统一的维护。 上面讲的是将异常展示到错误页面的方法,这其实只涉及到最后一层(Action)捕捉异常和业务逻辑层抛出异常的问题,而如何中间层内的异常如何抛、如何捕捉的问题考虑的思路一定是不一样的,不过,做应用系统的,业务逻辑层内部交叉引用的不多,所以这一块异常设计的矛盾并不突出。而如果你正在开发高度重用的组件甚至框架,异常就一定要好好设计一下了。 至于组件、框架的异常如何设计,我想只要去学JDK、Hibernate的那一套东西就没错了。能想到的就是,异常一定是调用者可以理解的,和方法的语义密切相关的。 最后,回到最初的问题,Why Checked Exception?我们讨厌它的主要原因其实还是它太令人迷惑了,太多人虽然整天又抛又接的,其实根本就没弄明白这里面是怎么一回事,其实你只要用不了一下午的时间冷静下来,看看例子稍微思考一下,就一定可以弄的很透彻。Anders举的例子其实很可笑的,他说底层方法抛出4个异常,随着梯子越来越高,你的方法大概需要声明40个异常,其实他一定没有写过Java程序,更没有设计过Java方法,异常只需要对本层方法的调用者有意义,调用者根本就不需要关心底层错误的细节,那方法干吗还要声明那些底层抛的异常呢?一定是自己在方法里面消化掉了嘛!(需要调用者作为错误处理的异常合并抛一个异常) |
|
返回顶楼 | |
发表时间:2003-12-24
muziq 看来是一个认真研究问题的人。Anders 确实有故意丑化 Java 的倾向。虽然我讨厌人身攻击,但是一些著名的大师也有掏糨糊的时候,毕竟都不是完人。所以我判断大师的标准就是看他在宣传自己的理论时是否有意在贬低别人的理论,如果是这样那他就不是我心目中的大师了。
|
|
返回顶楼 | |
发表时间:2003-12-24
呵呵,再一次在網上見到有朋友這 樣詳細討論會這問題
建議到這看一吧. http://www.mindview.net/Etc/Discussions/CheckedExceptions http://www.octopull.demon.co.uk/java/ExceptionalJava.html |
|
返回顶楼 | |
发表时间:2003-12-27
同意muziq的观点,是否异常对不同的观察者来说是不同的。对于用户而言,他要注册的用户名已经被人注册了就是异常,而对于程序员而言,这是业务逻辑的一部分。我偏向于站在用户的角度去观察,所以也赞同robbin的做法。至于对效率的影响,没有测试过,如果真的影响很大,可以考虑改变这种编程习惯。
|
|
返回顶楼 | |
发表时间:2004-01-08
我觉的转换为RuntimeException的方法就可以解决checked exception
checked exception的主要问题是容易导致层次过多, 所以对于不可恢复的exception, 在发生的第一点就做log或show message的处理, 然后转换为RuntimeException, 第一点以外的exception handler就会不做任何处理. 对于可以由用户或程序干预的可恢复的exception, 最好先进行预检查, 比如资源不在, 数组越界, 不要等exception发生后才处理. 另外还要结合event来进行处理可恢复的exception, 比如加个OnFileNotFindEvent, 外部程序在用这个类时就可以在event里写处理代码, 比如弹出个文件对话框什么的. 如果外部程序没实现这个event就做log或show message的处理, 转为RuntimeException抛出. 我不同意用Exception来处理用户登陆作为OO的一种方法, OO的方法是用event来做结果传递和选择步奏, 比如加OnInvlidUserNameEvent和OnLogonSuccessEvent到logon类里来处理登陆的流程. |
|
返回顶楼 | |
发表时间:2004-01-17
我最开始也是吧java的这套机制认为是java的一个优点。但从我实际编程来看。我越来越讨厌java的这个机制了。我倾向于spring的开发这Joshon的观点。大家可以在他那本书里看到他的评论。我决定说的太好了。我现在基本上就是是呀spring的jdbc包把sql异常全部变为runtime exception。所以我觉得checked exception真是设计的好,理论也好,但实际不好呀。(j2ee里面有很多这种东西)
|
|
返回顶楼 | |
发表时间:2004-02-15
看了这么多的讨论,结合自己的项目对异常处理也有一些自己的观点,大体上还是比较同意robbin的观点,同样的以robbin的例子来讲,用户登录时我会按以下的方法进行处理:
User login(username,password) throws LoginException{ if(!User.isExist(username)){ throw new LoginException("系统中不存在用户:"+username); } } 就上例说明对异常处理的基本观点,个人觉得从函数的功能方面来判断为佳,就应用系统而言,就是否存在用户这个非异常的分流来说,抛出异常有助于应用系统终端对于其的理解,就代码上而言也更为清晰,因为对于该函数而言这就是一个异常。 总而言之,个人觉得异常处理确实要慎重使用,需要从函数的功能上来判定以及该异常的作用而定。 |
|
返回顶楼 | |
发表时间:2004-02-18
其实异常分为两种,第一种程序异常,这一般是因为两种原因导致:程序BUG和某些访问异常(比如数据库访问、超时等),另外一种就是业务异常了,这种是对于不符合业务状态的操作进行人为处理。我非常同意dlee和robbin的看法。
我做过一个比较不错的异常处理机制,可以通过XML识别并描述异常,并采用国际化进行处理,这样,就可以将异常灵活解析。 |
|
返回顶楼 | |