|
![]() |
名片设计 CorelDRAW Illustrator AuotoCAD Painter 其他软件 Photoshop Fireworks Flash |
|
在这个开源框架大放异彩的时代,人们往往异常关注架构本身引入的各种新理念,而其非常处理机制经常被忽视。事实上,一个框架的非常处理方法是维持其稳定的基础。而且一个应用程序框架本身对非常的处理方法,也会对其使用者处理非常的方法造成深刻的影响。本文参考了一些大师对JAVA中非常使用方法的论述,并提出了几条简朴的见解,作为抛砖引玉之作,请大家共同探讨。 在JAVA中,非常实际上可以看作是方式的非正常返回值。例如 User getUser(String usrName)这个方式,本来应该返回一个用户对象,但是当非常出现时,方式并没有返回User,而是返回了一个Exception。这个非正常情况下的返回值就是非常。 本着非常就是方式的非正常返回值这种思想,可以对以下几个问题进行探讨: 1.什么时候应该使用(自定义)非常 2.应该使用已检查非常(CheckedException,我认为假如翻译为可控非常更加恰当),还是运行时非常(RuntimeException)。 什么时候应该使用非常: 关于自定义非常使用的时机,有一种传播的较为普遍的说法:非常只能用于处理“真正的非常情况”,不能参与流程控制,因为过多使用非常会造成性能的损失,因此在我们的系统中,应该尽量少使用自定义非常。 首先让我们考察一下什么是“真正的非常”。 一般情况下人们认为在操作系统一级(正确地说是JDK一级)抛出的非常就是“真正的非常”。然而所谓“系统级非常”和“应用级非常”在很多时候很难界定。例如对于一个文字处理软件来说,“NoEnoughSpaceException”这个非常毕竟是系统级的,还是应用级的?从系统的角度来看,磁盘空间不够,应属于系统级非常。但从应用的角度看,文件无法保存了,也是应用级非常。因此我认为这种分类方式从分类学角度来说是不科学的:所谓“系统级”和“应用级”的范围常常会互相覆盖。 另外一种较注意实效的看法是,从方式的功能角度看,决定是否应该使用非常。结合前面的“非常事实上是一种特别返回值”的说法,举例如下: User getUser(String usrName) ,使用者期望得到User对象,但是假如真的有特别情况发生,而使用者又没有进行事先判定,那么我们只能抛出非常。在这里可能抛出的非常是一个自定义的非常:“用户不存在”。 boolean isUserExist(String usrName) ,使用者是在判定用户是否存在,所以我们当然没有必要抛出“用户不存在”非常,只需返回一个布尔值即可。 void registUser(String usrName),这个方式没有返回值,因此假如出现了非常情况,只能抛出非常。这里可能抛出的非常有“用户名已用”、“系统禁止注册”等。 我认为第二种使用非常的方式是较科学且较直观的:一切从实效出发。在这种做法的指导下,我们可能会在系统中使用大量自定义非常。 有人认为非常不应该参与流程控制,并将这种参与流程控制的非常讽刺为“SuperIf”。关于此问题我们可以参考RUP中关于非常事件流的论述, RUP的结论是“非常情况是现实中客观存在的一类事件,当我们必须对它进行处理时,这个处理就发生在非常流中”。因此在JAVA中将非常作为一种流程控制手段,和RUP的非常流概念不谋而合,且对非常的处理就可以在非常块中进行。 有人可能害怕大量使用非常会带来性能上的损失。性能问题是另外一个需要庞大篇幅论证的问题,大家可以参考Rod Johnson在他的《J2EE Without EJB》一书中对性能优化的分析。简而言之是一句话:一切语言级优化所作的努力,在一次I/O或者数据库读写操作中将化为乌有。因此对非常使用带来的小小性能损失,实在是不需“言必性能”。 使用已检查非常还是运行时非常: 这个问题的争议较大,比较极端的如Bruce Eckel和Anders Hejlsberg,认为应该取消一切CheckedException,以带有自定义消息的RuntimeException替代之,Bruce甚至亲自给出一段代码告诉大家如何将CheckedException转为RuntimeException。而James Gosling则使用CheckedException过了火,有人讽刺James:在他的眼里,用户都是上帝,有能力且必须处理诸如“IOException”这类谁也没有办法的事情。Rod Johnson比较中庸,他认为CheckedException有其有用之处:类似James Gosling说的,当用户必须对某种特别情形作出反应的时候,我们可以使用CheckedException来提醒用户“这种情形可能会发生,你要对它进行处理”。 但是Rod极大的缩小了这种情形发生的范围,他认为只有当非常流必须被特别处理的时候,才有使用CheckedException的需求。举例来说,int registUser(String usrName)方式用于注册用户。这个API的作者规定,当返回值为0时,代表注册成功;返回值为1,代表用户名已用;返回值为2,代表系统禁止注册…… 在这种情况下,就应该使用CheckedException,而不是RuntimeException或简朴返回值。因为除了0的每个返回值都代表了一条非常流,且每个非常流都要进行特别处理,比如用户名已有时,我们可能要自动转入一个提醒页面,提醒用户其他可用的用户名;禁止注册时,我们要进入一个公告页面,这个页面展示了禁止注册的原因及开放时间等等。 对上面的情况,可以做一个更精确的总结:只有当非常参与了流程控制时,才应该使用CheckedException。 那么我们如何判定非常是否应该参与流程控制?这种判定可以从需求入手。假如需求要求我们,在这条非常流上,要进行A处理,在那条非常流,要进行B处理,则很明显,这里应该使用CheckedException来控制流程。假如需求只是“假如发生了非常,在界面上进行提示”,那么这种情况下,我们就没有必要使用CheckedException,只要使用带有消息的RuntimeException即可。 使用CheckedException有一个显著的问题,因为每个使用者都必须对方式法抛出的CheckedException作出响应,因此一旦方式已经被广泛使用,要添加一个新的CheckedException就变得十分困难:每个使用者都要做出相应的修改。但是从另一个角度看,假如你添加CheckedException的理由确实是“需求要求如此,我们必须对它进行特别处理”,则每个方式的使用者就应该增加一个新的catch,并增加这种新的特别处理。 这个问题也提醒我们,使用CheckedException时,一定要确定是否这种情况需要“特别处理”,否则尽量以RuntimeException进行代替。 返回类别: 教程 上一教程: ibm developer的一些对我有用的网址 下一教程: Annotations:hype or not? 您可以阅读与"JAVA中非常使用范围的一些思索"相关的教程: · Java的一些类的使用经验 · java与c/c++进行socket通信的一些问题(1) · java中轻易搞错的一些东东 · java与c/c++进行socket通信的一些问题(2) · 我学习使用JAVA的一点体会 |
![]() ![]() |
快精灵印艺坊 版权所有 |
首页![]() ![]() ![]() ![]() ![]() ![]() ![]() |