一,Java 异常处理及异常机制介绍

当出现程序无法控制的外部环境问题(用户提供的文件不存在,文件内容损坏,

网络不可用 ... )时, JAVA 就会用异常对象来描述。

JAVA 中用 2 种方法处理异常:

1 在发生异常的地方直接处理;

2 将异常抛给调用者 , 让调用者处理。

JAVA 异常可分为 3 种:

(1) 检查性异常 :java.lang.Exception

(2) 运行期异常 :java.lang.RuntimeException

(3) 错误 :java.lang.Error

顶层是 java.lang.Throwable 类,检查性异常,运行期异常,错误都是这个类的

子孙类。

java.lang.Exception 和 java.lang.Error 继承自 java.lang.Throwable, 而

java.lang.RuntimeException 继承自 java.lang.Exception.

 

 

检查性异常

------ 程序正确,但因为外在的环境条件不满足引发。

例如:用户错误及 I/O 问题 ---- 程序试图打开一个并不存在的远程 Socket

端口。这不是程序本身的逻辑错误,而很可能是远程机器名字错误 ( 用户拼写错

误 ) 。对商用软件系统,程序开发者必须考虑并处理这个问题。 JAVA 编译器强制

要求处理这类异常,如果不捕获这类异常,程序将不能被编译。

 

运行期异常

------ 这意味着程序存在 bug ,如数组越界, 0 被除,入参不满足规范 ..... 这

类异常需要更改程序来避免, JAVA 编译器强制要求处理这类异常。

错误

------ 一般很少见,也很难通过程序解决。它可能源于程序的 bug ,但一般更

可能源于环境问题,如内存耗尽。错误在程序中无须处理,而有运行环境处理。

如何处理异常?

1.try...catch

程序运行产生异常时 , 将从异常发生点中断程序并向外抛出异常信息。

Java 代码

int x = (int)(Math.random()*5);

int y = (int)(Math.random()*10);

int[] z =new int[5];

try{

System.out.println("y/x="+(y/x));

System.out.println("y="+y+"z[y]="+z[y]);

} catch (ArithmeticException exc1) {

System.out.println(" 算术运算异常 :"+exc1.getMessage());

} catch (ArrayIndexOutOfBoundsException exc2) {

System.out.println(" 数据越界异常 :"+exc2.getMessage());

}

说明 :

ArithmeticException( 算术异常 ) 和 ArrayIndexOutOfBoundsException( 数

组下标越界异常 ) 都属于 java.lang.RuntimeException (运行期异常),如果不用

try...catch 捕获,程序也是可通过编译的,但如果属于 java.lang.Exception (检

查性异常),必须而且一定要用 try...catch... 对其进行处理。

2.finally

如果把 finally 块置 try...catch... 语句后, finally 块一般都会得到执行,它相

当于一个万能的保险,即使前面的 try 块发生异常,而又没有对应异常的 catch

块, finally 块将马上执行。

以下情形, finally 块将不会被执行:

(1)finally 块中发生了异常;

(2) 程序所在线程死亡;

(3) 在前面的代码中用了 System.exit() ;

(4) 关闭 CPU

 

 

3. 多个异常的处理规则:

定义多个 catch 可精确地定位异常。如果为子类的异常定义了特殊的 catch

块,而父类的异常则放在另外一个 catch 块中,此时,必须满足以下规则:子类

异常的处理块必须在父类异常处理块的前面,否则会发生编译错误。所以,越特

殊的异常越在前面处理,越普遍的异常越在后面处理。这类似于制订防火墙的规

则次序:较特殊的规则在前,较普通的规则在后。

4. 自行抛出异常

在程序中自行抛出异常使用 throw 语句。

throw 语句抛出的不是异常类,而是一个异常实例,而且每次只能抛出一个异常

实例。

throw 语句的语法格式: throw ExceptionInstance;

方法是 2 步:创建异常,抛出异常 ( 首先实例化一个异常对象 , 然后用 thow 抛出 )

合在一起就是 ----throw new IOException(" 异常说明信息 ") 。将创建异常,抛出异

常合在一起的好处是:创建异常时,会包含异常创建处的行信息,异常被捕获时

可以通过堆栈迹 (stack Trace) 的形式报告这些信息。如果在同一行代码创建和抛

出异常,对于程序的调试将非常有用。

所以, thow new XXX() 已经成为一个标准的异常抛出范式。

在定义一个方法时,方法块中调用的方法可能会抛出异常,可用上面的 throw

new XXX() 处理,如果不处理,那么必须在方法定义时,用 thows 声明这个方法

会抛出的异常。

对异常的处理,有一条行之有效的默认规则:向上抛出 ----- 被调用类在运行过程

中对遇到的异常一概不作处理,而是直接向上抛出,一直到最上层的调用类,调

用类根据应用系统的需求和特定的异常处理规则进行处理,如向控制台输出异常

堆栈信息,打印在日志文件中。用一句形象的话来说,就是谁使用,谁 ( 最上层

的调用类 ) 处理。

 

Question 63

Given the exhibit:

What is the result?

A. test

B. Exception

C. Compilation fails

D. NullPointerException

考点:

异常捕获的顺序

考点说明:

处理异常的一个原则:“先处理小异常,再处理大异常”。

对异常进行捕获时,我们应总是把对 Exception 类的 catch 块放在最后。如

果我们把 Exception 对应的 catch 块排在其他 catch 块的前面, Java 运行时将直

接进入该 catch 块(因为所有异常对象都是 Exception 或其子类的实例),而排

在它后面的 catch 块将永远也不会获得执行的机会。

本题详解:

Exception 的 catch 块应放在 NullPointerException 的 catch 块后面。

 

 

Question 54

Given the exhibit:

What is the

result if NullPointerException occurs on line 34?

A. c

B. a

C. ab

D. ac

E. bc

F. abc

考点:

异常的执行流程

考点说明:

当程序中抛出一个异常后,程序从程序中导致异常的代码处跳出, java 虚拟

机检测寻找和 try 关键字匹配的处理该异常的 catch 块,如果找到,将控制权交

到 catch 块中的代码,然后继续往下执行程序, try 块中发生异常的代码不会被

重新执行。如果没有找到处理该异常的 catch 块,在所有的 finally 块代码被执行

和当前线程的所属的 ThreadGroup 的 uncaughtException 方法被调用后,遇到

异常的当前线程被中止。

finally 关键字保证无论程序使用任何方式离开 try 块, finally 中的语句都会

被执行。在以下三种情况下会进入 finally 块:

( 1 ) try 块中的代码正常执行完毕。

( 2 ) 在 try 块中抛出异常。

( 3 ) 在 try 块中执行 return 、 break 、 continue 。

因此,当你需要一个地方来执行在任何情况下都必须执行的代码时,就可以

将这些代码放入 finally 块中。当你的程序中使用了外界资源 , 如数据库连接,文

件等,必须将释放这些资源的代码写入 finally 块中。

本题详解:

在 line34 处产生一个 NullPointerException ,代码会从产生异常的地方跳出,

然后找匹配 NullPointerException 的 catch 块,执行该 catch 块中的代码,输出

a ,执行完之后程序再进入 finally 块,执行 finally 块中的代码,输出 c 。

 

 

Exhibit:

Given the exhibit:

25. try{

26.

A a = new A();

27.

a.method1();

28. } catch(Exception e){

29.

System.out.print(“an error occurred”);

30. }

Which two statements are true if a NullPointer Exception is thrown on line 3 of

class C?(choose two)

A. The application will crash.

B. The code on line 29 will be executed

C. The code on line 5 of class A will execute.

D. The code on line 5 of class B will execute.

E. The exception will be propagated back to line 27.

考点:

异常的传播

考点说明:

面向对象的应用程序运行时,经常会发生一系列方法调用,从而形成“方法

调用栈”,异常的传播则相反:只要异常没有被完全捕获(包括异常没有被捕获,

或异常被处理后重新抛出了新异常),异常从发生异常的方法逐渐向外传播,首

先传给该方法的调用者,该方法调用者再次传给其调用者„„直至最后传到

main 方法,如果 main 方法依然没有处理该异常, JVM 会中止该程序,并打印

异常的跟踪栈信息。

本题详解:

本题中, C 类的 method3 方法中产生一个异常,向上传播给其调用者 B 类

的 method2 方法,再传播给上一层调用者 A 类的 method1 方法。调用者 a 在调

用 method1 时对异常进行了捕获,并且捕获异常的范围是 Exception ,因此 catch

块中的代码,即 line29 ,会得到执行。