要注意的是,使用 Exception 并不会让你在检测、报告和处理错误时更省力,但是可以让你把这些工作组织起来更高效。优势 2:在调用栈中向上传播错误 Exception 的第二个优势就是,可以把错误报告给调用栈的上层方法。假如在主程序中,在一系列嵌套的调用方法中,readFile 方法是第四个方法: method1 调用 method2,然后调用 method3,最后调用 readFile。
- readFile {
- try {
- open the file;
- determine its size;
- allocate that much memory;
- read the file into memory;
- close the file;
- } catch (fileOpenFailed) {
- doSomething;
- } catch (sizeDeterminationFailed) {
- doSomething;
- } catch (memoryAllocationFailed) {
- doSomething;
- } catch (readFailed) {
- doSomething;
- } catch (fileCloseFailed) {
- doSomething;
- }
- }
- method1 {
- call method2;
- }
- method2 {
- call method3;
- }
- method3 {
- call readFile;
- }
假设 method1 是唯一关心在 readFile 内发生了什么错误的方法。传统的错误通知技术强制 method1 和 method2 传播 readFile 返回的错误代码,直到错误代码最后传到 method1——而 method1 是唯一需要返回码的方法。
- method1 {
- errorCodeType error;
- error = call method2;
- if (error)
- doErrorProcessing;
- else
- proceed;}
- errorCodeType method2 {
- errorCodeType error;
- error = call method3;
- if (error)
- return error;
- else
- proceed;}
- errorCodeType method3 {
- errorCodeType error;
- error = call readFile;
- if (error)
- return error;
- else
- proceed;}
回忆一下,Java 运行时系统通过逆向搜索,查找对某个异常感兴趣的任何方法。一个方法可以躲避任何抛给它的异常,从而让一个方法可以把异常抛到更远的调用栈中捕获。因此,只有关心错误的方法,才必须要去检测错误。
然而,正如伪代码所示,中间人方法可以躲避掉后面必须要处理的异常。一个方法通过在 throws 从句中进行声明,可以抛掉任何检查异常。优势 3:归类和区分错误类型因为程序抛出的所有异常都是对象,类是有层次结构的,所以对异常进行归类或分组是非常自然的结果。在 Java 平台中有一个例子,一组相关异常被定义在 java.io 包——IOException 及其子类。IOException 是最通用的,它代表了我们在执行 I/O 相关操作的时候发生的任何错误类型。它的继承者代表了更加细分的错误。例如,FileNotFoundException 表示一个文件不能再磁盘中定位到。一个方法可以写一个具体的处理器,能处理一个十分具体的异常。由于 FileNotFoundException 没有继承者,所以下面的这个异常处理器只能处理一种类型的异常:
- method1 {
- try {
- call method2;
- } catch (exception e) {
- doErrorProcessing;
- }
- }
- method2 throws exception {
- call method3;
- }
- method3 throws exception {
- call readFile;
- }
一个方法也可以用更通用的处理器捕获处理具体的异常。例如,为了捕获所有的 I/O 异常,不管具体的类型是什么,只要给异常处理器指定一个 IOException 参数就行。
- catch (FileNotFoundException e) {
- ...
- }
这个处理器可以捕获所有的 I/O 异常,包括 FileNotFoundException,EOFException 等等。你可以通过查询传给异常处理器的参数,发现错误发生的细节。例如,用下面的代码打印堆栈跟踪信息:
- catch (IOException e) {
- ...
- }
- catch (IOException e) {
- // Output goes to System.err.
- e.printStackTrace();
- // Send trace to stdout.
- e.printStackTrace(System.out);
- }
你甚至可以构建一个可以处理所有异常的异常处理器:
在 Throwable 类层级结构中,Exception 类已经快接近顶点了。所以这个处理器将会捕获很多它不想捕获的异常。如果你想在整个程序中对所有异常都采取统一处理方式,你就可能会采取这种办法处理异常,例如,给用户打印错误信息并退出。然而在大多数情况下,你希望异常处理器越具体越好。理由是在你决定最佳的恢复策略之前,你首先要知道错误的类型。事实上,如果不捕获具体的错误,这个处理器就必须要容纳任何可能性。太通用的异常处理器可能会让代码更容易出错,因为它们会捕获和处理程序员意料之外的异常,这样就超出处理器的能力范围了。就像前面说过的,你可以创建一组异常,然后采用通用处理的风格。或者你可以使用具体的异常类型来区分不同的异常,然后用精确的风格处理异常。
- // A (too) general exception handler
- catch (Exception e) {
- ...
- }
转自:
来源: http://www.bubuko.com/infodetail-1969927.html