Exception和继承自Exception的RuntimeException有什么区别呢?
Java compiler要求所有的Exception 要么被catch,要么被throw,除非这是一个RuntimeExeption (e instanceof RuntimeException)。也就是说,通常的Exception一定要被处理,也即我们所说的 checked exception,而RuntimeException不强制要求处理,(当然你自己要处理也可以),所以我们称为unchecked exception。
之所以区分 checked/unchecked exception,JAVA的设计思想是区分从类/方法设计者角度来看两种不同的异常:
一种是设计者认为这个方法在使用过程中使用者能够处理的异常,这些往往作为checked exception。比如一个IO系统的设计者会认为诸如物理文件不存在或者介质无法读取等异常时很可能发生,而使用者完全可能捕获这个异常,通过让用户重新输入文件名等方式重新进行这个操作,也就是说,这是一个可恢复的操作。所以我会在诸如 read()/write()等操作中throw 一个 IOException(checked exception)。
第二种是设计者认为使用者不能够处理的异常,比如我写一个函数要求传入的参数是个正数,那么当我发现使用者传了个负数进来时,合理的预期是程序中出bug了。如果我抛出一个异常描述这件事,即使我要求调用者捕获这个异常,他肯定也不知道该怎么办(总不能随便传一个正数进来吧)。这时候我就会抛出一个IllegalArgumentException(uncheck exception),这里面的潜台词是:小子,我知道你也是帮人背黑锅的,处理不了这个,你还是交给你的领导(调用你的程序)去处理这个异常吧。 同理,当JVM发现除数为0时,抛出的ArithmeticException也是一个unchecked exception。
从这里可以看出,checked exception和 unchecked exception的根本区别在于设计者认为使用者是否能够并且应该处理这个异常。不幸的是,由于Java使用者水平的参差不齐,大量的unchecked exception该被设计成了checked exception,而对于真正的checked exception,又有太多被catch了之后啥都不作就悄无声息了。尤其是不声不响吞噬exception的行为,不但达不到设计者本来的要求(进行恢复处理),甚至问题更大(连 unchecked exception那种最后报错的效果都没了)。
所以, C#在异常处理上采用了完全不同的思路,把所有的的exception都设计为 unchecked exception,也就是说,它基于这样一种思路: 我不要求任何人处理任何异常;如果你能处理,那么你就显示catch这种异常;如果某种异常没有人catch,那么系统最终会崩溃。
转自:http://www.iteye.com/problems/40984
----------------------------------------------------------------------------------------------------------------------------------------------
看到有一些人发帖问Exception和RuntimeException的区别,这个问题当然不难,因为RuntimeException是Exception的子类。
问的人当然不是想得到那么简单的答案,那么这就是涉及到了一些设计者的思想在里面,我整理了一下,水平有限,仅供参考:
每一种语言都有不同的异常机制,在理解Java的异常机制之前,先了解一下C#的异常机制,以便于对Java的理解:
C#的异常处理不同于Java的异常机制,它将所有的异常都设置成RuntimeException异常,不要求使用者在编译的时候就人工处理(catch捕获)或者警惕知晓(throws抛出),当然也提供了try机制给高级使用者。它的思路就是:我并不区分异常,不要求任何人处理任何异常,如果你要处理并有能力处理,那么我提供你处理方式(catch),对于普通的使用者,遇到的异常都交给虚拟机来处理。C#的这种做法简化了异常机制,使语言易于理解。这也是我个人认为比较好的异常处理机制。
在了解了C#的异常机制,就可以很容易理解Java的异常机制。Java设计者将一部分异常定义为非RuntimeException,强迫使用者在编译的过程中就必须要处理:(catch捕获)或者警惕知晓(throws抛出)。另一部分定义为RuntimeException,不强迫使用者在编译过程中处理。
为什么会区分这两种异常?第一种异常是因为Java设计者认为有些异常使用者能够处理,这就是编译异常(非RuntimeException子类的异常),你要么自己catch处理,也可以抛给虚拟机,总之你需要知道这个异常警示。
非RuntimeException子类的异常是Java语言设计者认为很有可能出错的情况下,提前在编译时期就警告用户的一种机制。这种异常在编译时期就会报错,我们必须在编译的时候进行处理,要么try要么抛出,调用的方法如果抛出了,那么调用这个方法的方法(可能是主方法)要么try或者抛出,如果一路抛出,并不是解决问题,只是逃避了解决方法,交给了虚拟机去解决,只有try catch是真正的手动解决问题。比如DateFormat类中的parse方法:
public Date parse(String source) throws ParseException
这种情况应对了Java语言中的异常机制,因为这里很容易犯错,只要给出的字符串日期格式有一点不同,就会出错,所以Java语言设计了一种异常:ParseException提醒用户在编译的时候就必须要处理,try或者抛出,人工try的话可以在真的出现这种错误之后不阻断后面的语句。而另一种处理方法抛出异常是回避人处理错误,将错误交给虚拟机处理,虚拟机遇到错误就会中断,影响后面的程序执行。
而另外一种RuntimeException异常是设计者认为使用者不能够处理的异常,原因多种多样,可能认识不到发现不了等。这种异常不会强制使用者提前(catch捕获)或者警惕知晓(throws抛出),会在执行的时候,才报出错误让使用者知晓。
深入来说:RuntimeException,这种异常的机制就是在编译时期不会报错,如果有错误可以在运行的时候发现,这种异常主要针对在语法上没有错误的异常,比如除以0。当然也是可以提前预料到这种错误,人工catch出限定除数的范围,自定义一个异常作为筛选用来检查除数是否为0,在除数为零的时候,会给出异常反馈。总之对待RuntimeException也可以像对待非RuntimeException一样人工catch,只不过Java不强制而已。
这种机制有利有弊,使用者参差不齐,有些人在被强制catch时,什么也不做,无视设计者的理想,这样反而会导致更多的问题。作者的理想情况并没有理想的出现,而且这让Java语言的使用变得啰嗦麻烦,是一个被人诟病的地方。当然Java的这种做法的优势就是将业务逻辑和异常处理区分开,在实际开发中是很有帮助的。
总之:Java的异常机制对应了设计者对不同的异常的划分设置。至于好用不好用,看使用者的喜好了。 |
|