对java异常的辨论

原创 2004年10月23日 12:25:00


  现在我将辩论的问题,是到底还要不要使用“检查型异常”。

  我们如果使用“检查型异常”,那么我们在调用有异常方法的时候,就不得不将这方法放入到try-catch块中去,而不论我们是否真的就要在这儿把这个异常给解决掉。一个可行的办法就是,我们如果不需要处理,那么我们可以捕捉后在catch块中使用e.fillInStackTrack()方法将它往上抛,而且还可以保持异常产生到捕捉的轨迹不丢失。不过就算是这样,很明显还是很麻烦,是一个效率低下的办法。我们每天得处理很多这样的异常,真是太麻烦了,所以,很多人反对使用“检查型异常”。
  使用“检查型异常”时很容易犯的一个错误就是丢失异常。当我们把一个有有异常声明的方法放到try块中去后,不管我们是否有catch捕捉到它,或是捕捉到后是否有处理,异常处理机制都会默认这个异常已经得到正确的处理了。如:
try {
} finally{
}

try{
} catch(Exception ex) {
//这儿并不做任何事情,异常就这样在这儿消失了,但是根本没有得到有效的处理。
}
  有人提出对“检查型异常”进行下面类似的包装:
class WrapCheckedException {
  void throwRuntimeException() {
    try {
       throw new AMyselfException("Where am I?");
    } catch(Exception e) { // Adapt to unchecked:
      throw new RuntimeException(e);
    }
  }
}
  这样我们调用这个方法的时候,不用把它放入try中去,异常也会被捕捉。而当我们需要在catch块中捕捉它并进行处理的时候,能够使用getCause()方法,如:
catch(RuntimeException re) {
        try {
          throw re.getCause();
        } catch(AMyselfException e) {
          e.printStackTrace();
        }
  不过我觉得这样的包装实在是非常的滑稽。因为这儿在方法中抛出的异常是一个运行期异常,我们以后调用这个方法的时候,根本不知道这个方法会抛出一个怎样的异常,那么我们又怎么会catch(AMyselfException e)呢?

  而“检查型异常”附加的那些异常说明(throws)虽然使程序多了一些代码,但当我们不仅仅是要报告发生了一个异常,而且我们还要根据发生了某某异常,而对异常进行处理的时候,这个特别的说明就对我们非常有用了。如果是“非检查型异常”的话,我们根本就不知道我们调用的方法会发生一个具体什么类型的异常,我们最多就是知道这个方法会抛出一个异常。这样的话,我们又如何对异常进行正确的处理?

  我们看到,对异常的附加说明是不能够取消的。如果我们一旦取消了这个对异常的说明,那么我们每次想对异常进行处理的时候,不得不再去方法中找到那个抛出异常的地点,看到底是抛出了一个什么具体类型的异常。如果这个方法是第三方库中的方法,而又没有对这个方法将抛出的异常的说明,那么你不得不去询问第三方库生产商。这时候,第三方有可能也需要去检查源代码,才知道那个方法到底抛出了什么类型的异常。可以看到,这样将会造成许多非常麻烦的后果。而如果我们在方法名尾部紧跟了一个对方法将会抛出的异常的说明,那么那么将很轻松的知道我们要处理的方法会抛出什么类型的异常。问题是现在的异常处理机制,每次调用有异常说明的方法的时候,都必须把这个方法放入try块中,这样实在是非常的烦恼。

  从上面我总结出来一个综合的异常处理方案:由于考虑到java的向后兼容性,我们现有的异常机制不能进行彻底的动摇。那么,我们可以通过在方法后新增加一个子句,用来说明那些方法中将要抛出的“非检查型异常”。这样的话,调用一个只有“非检”说明子句的方法,我们是不需要将之放入try块中去的。而我们想要更具体的处理异常的时候,我们也能将这方法放入try块中,然后进行捕捉。具体需要捕捉哪些异常呢?在方法的“非检”说明中都有,这样不是很方便吗?

  如果以后的异常处理机制进行了上面的改造,那么我们又有一个问题需要提出来。这个问题就是,什么时候我们需要在方法中抛出“检查型异常”?现在在网上也有很多争论,在我看到的中间,有很多都认为“检查型异常”可以不用,是一个java中的一大失败。但我不这么认为,可是我需要一个使用“检查型异常”的理由,给“检查型异常”一个存在的空间。

  下面有一个经常发生在我们代码中,但是却十分有趣的现象:
void foo() {

    InputStream in = null;
    OutputStream out = null;

    try {
        in = new FileInputStream("foo1.txt");
        out = new FileOutputStream("foo2.txt");

        // do some stuff with in/out

    } catch (IOException e) {
        println("something bad happened");
    } finally {
        if (in != null) {
            try {
                in.close();
            } catch IOException(e) {
                println("whooops!");//very crazy!!!
            }
        }
        if (out != null) {
            try {
                out.close();
            } catch (IOException e) {
                println("whooops 2!");
            }
        }
    }
}

  在上面的代码中我们看到,如果文件没有成功关闭,那么我们还需要写一个try块来处理它,但是这个问题是不可能得到处理的。在这个问题中,我们需要的只是文件没有被关闭这个报告就行了,而且只能做到这样。那么我们完全可以用一个“运行期异常”来代替原来的这个“checked Exception”。这个例子也让我们看到一些人说“运行期异常”在JAVA中完全没有用武之地是错误的观点。

  使用“检查型异常”中有一个“bubbling up”的问题。例如:我有一个f()方法,throws exA,exB,exC,exD异常。常常我们偷懒写成throws Exception,这样做非常不好。

  使用“Checked Exception”还带来很多的抱怨。例如:我们在方法f()中throws Exception,但是在方法内部,我们并没有throw异常,甚至也没有必要throw异常,也许我们根本不需要,也许我们是为了以后可能发生做好防备。但是,我们在调用f()方法的时候,不管我们愿意还是不愿意,编译器都要求我们把这个方法放入try块中,真是烦恼至极,而且听说在sun的类库中还经常有这样的问题存在。


下面这些内容摘自thinking in java第三版:

Exception guidelines

Use exceptions to:

  1. Handle problems at the appropriate level. (Avoid catching exceptions unless you know what to do with them).

    在合适的地方处理异常(避免在不知道该如何处理的情竞下去捕捉异常)。
  2. Fix the problem and call the method that caused the exception again.

    解决掉问题,然后重新调用引发问题的方法。
  3. Patch things up and continue without retrying the method.

    修正一下问题,然后绕过那个方法再继续。
  4. Calculate some alternative result instead of what the method was supposed to produce.

    用一些别的计算结果,而不是那个方法将返回的结果。
  5. Do whatever you can in the current context and rethrow the same exception to a higher context.

    把当前你能做完的事情做完,然后把相同的异常抛到更高层。
  6. Do whatever you can in the current context and throw a different exception to a higher context.

    把当前你能做完的事情做完,然后抛一个不同的异常到更高层。
  7. Terminate the program.

    中止程序。
  8. Simplify. (If your exception scheme makes things more complicated, then it is painful and annoying to use.)

    简化(如果你的异常把事情搞得更复杂,那用起来将非常的烦恼和痛苦)。
  9. Make your library and program safer. (This is a short-term investment for debugging, and a long-term investment for application robustness.)

    使你的类库和程序更安装(这既是为调试做短期投资,也是为程序的健壮性做长期投资)。

java:对输入数据的异常处理

import java.util.Scanner; public class ExceptionTest1 { void inputException() { ...
  • YanXiaoJu17
  • YanXiaoJu17
  • 2017年11月01日 20:01
  • 208

谈谈Java异常的理解

所谓异常就是程序运行时,常出现的非正常现象。 Java中的异常都是继承Throwable基础, 异常分为error和exception, error是系统发生异常,也就是JVM编译解决不了的问题...
  • qq_35447305
  • qq_35447305
  • 2017年07月09日 13:01
  • 269

浅谈我对Java异常类的了解

相信大家在学习Java 程序的时候,总会遇见一些问题,这些问题导致了异常的发生,随之就有了异常的处理。 首先,什么是异常 ?  其实异常就是对问题的描述,将问题封装成对象,当问题出现时,就会调用该对象...
  • xoptimal
  • xoptimal
  • 2014年12月22日 22:54
  • 588

JAVA操作数组的异常

        数组是程序员经常会用到的数据结构。在进行数组操作如复制时有可能会产生三种异常。 NullPointerException        这个异常的产生可能是因为源数组或是目的数组...
  • wdhSoft
  • wdhSoft
  • 2007年04月23日 16:47
  • 2418

Java异常处理与垃圾回收

1.异常的概念 Java 异常是Java提供的用于处理程序中错误的一种机制。 所谓错误是指在程序运行的过程中发生的一些异常事件(如:除0溢出,数组下标越界,所要读取的文件不存在)。 设计...
  • Mustango
  • Mustango
  • 2016年09月04日 16:40
  • 426

Java中的异常对程序效率有无影响

当异常没有发生时,没有影响。 其实从异常实现的角度来看,在throw语句处,跳转到异常的处理代码,不同的异常处理,应该类似C++中的虚函数表一样的数构结构(待考证)。 所以如果没有抛出异常,那和普...
  • hengyunabc
  • hengyunabc
  • 2012年05月14日 01:52
  • 3578

Effective Java学习笔记: 第58条 对可恢复的情况使用受检异常,对于编程错误使用运行时异常

java提供了三种可以抛出的结构: 1. 受检异常(checked exception) 2. 运行时异常(runtime exception) 3. 错误(error) 运行时异常和错误...
  • WLFIGHTER
  • WLFIGHTER
  • 2016年09月17日 17:16
  • 291

Java 进阶:异常影响性能吗?

Java 进阶:异常影响性能吗?曾经在给一个业务系统增加限流功能,使用的限流组件在流量超过阈值时,会直接抛异常,异常导致 CPU 占用率飙升。第一次遇到这样的情况,让我们不得不思考,异常怎么会对性能造...
  • hustspy1990
  • hustspy1990
  • 2017年09月24日 10:31
  • 805

JAVA异常架构图及面试题、及其断言

error表示系统级的错误,是java运行环境内部错误或者硬件问题,不能指望程序来处理这样的问题,除了退出运行外别无选择,它是Java虚拟机抛出的。 exception 表示程序需要捕捉、需要处理的...
  • JavaWebRookie
  • JavaWebRookie
  • 2016年11月25日 17:09
  • 1291

JVM学习-java内存区域与异常

java是一门跨硬件平台的面向对象高级编程语言,java程序运行在java虚拟机上(JVM),由JVM管理内存,这点是和C++最大区别;虽然内存有JVM管理,但是我们也必须要理解JVM是如何管理内存的...
  • wenhuayuzhihui
  • wenhuayuzhihui
  • 2016年07月21日 13:14
  • 1542
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:对java异常的辨论
举报原因:
原因补充:

(最多只允许输入30个字)