4、Java异常处理
4.1 Java异常概念
Java异常是Java提供的用于处理程序中错误的一种机制。
所谓错误是指在程序运行的过程中发生一些异常事件(如:除0溢出,数组下标越界,所要读取的文件不存在)。
设计良好的程序应该在异常发生时提供处理这些错位的方法,使得程序不会因为异常的发生而阻断或产生不可预见的结果。
Java程序的执行过程中如出现异常事件,可以生成一个异常类,该异常类封装了异常事件的信息并将被提交给Java运行时的系统,这个过程称为抛出(throw)异常。
当Java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。
4.2 异常类型
Throwable
Error Exception(IOException、RuntimeException)
4.3 Java的内置异常
除了java.lang包里定义的异常处理外,在其它java包中还有异常处理。其实,几乎每个java包里都有相应的异常类来处理相应的异常,但是RuntimeException异常以及其派生的子类是不用处理的,多少从RuntimeException里派生的异常都可以自动调用。注意:我们在处理异常时,可以用catch来捕捉异常,即在运行过程中如果系统发现异常就会将其捕捉下来进行人为的处理;也可以用throw来抛出异常,即在运行过程中某个语句出现了异常如找不到文件等,系统会自动抛出该异常而继续向下运行程序。这两种方式各有千秋,通过捕捉异常我们可以更清楚地了解程序运行中存在的异常,以便我们更好的改进;抛出异常可以保证程序的正常运行。但在此提醒大家还是选择catch异常,这样如果这个软件以后有什么bug也好处理。给大家举个例子,就像我们的ATM机一样,如果我们在取钱过程中程序运行出现异常,我们当然是希望系统抛出异常,以便我们向银行反映情况来解决我们遇到的问题,这种方式就是catch异常的好处之一。同时,如果是抛出异常,系统会抛出一大堆专业的术语来,这样用户会怎样想,大家可以想象一下,如果一个人去取钱,突然间屏幕上显示一大堆我们Java语言抛出异常时的专业术语,这个会怎么想。所以,通过catch异常,我们可以修改异常提示语以便用户更好地理解。我们再以取钱为例,如果我们选择程序抛出异常,如果一个人去取钱,突然间程序运行出现异常,但这个异常被抛出了,但现在的问题是抛出后在不知不觉间你的银行卡余额变少了你会怎么想。所以,建议大家在写程序时尽量选择catch异常。
4.4 Java异常举例
import java.io.*;
public class TestEx {
public static void main(String[] args) {
try {
System.out.println(2 / 0);
} catch (ArithmeticException ae) { // 自己定义的异常类对象名,系统将异常对象传递给ae里面,ae相当于形参
System.out.println("出错了");
ae.printStackTrace();// 常用的办法:把错误的堆栈信息打印出来!系统默认也是打印误的堆栈信息。
}
}
}
运行结果:
出错了
java.lang.ArithmeticException: / by zero
at TestEx.main(TestEx.java:7)
4.5 异常的捕获和处理
在Java语言的异常处理机制里面包括异常捕获和异常处理两部分。通过异常处理我们可以人为地处理捕获到的异常,当然也可以通过相应的方法来处理。
捕获并处理异常语句格式如下:
try {……; } //可能引发异常的语句
catch(Exception1 e1) {……; }//对异常进行处理
catch(Exception2 e2) {……; }
......
finally {......; } //异常处理结束前的执行程序体
4.6 异常抛出
4.6.1 throw语句
在Java语言中throw语句主动产生一个异常,当程序执行到throw语句时会抛出一个异常,然后将控制转到一个相应的catch代码块。如果当前方法中没有catch模块,那么Java虚拟机将控制转到调用这个方法的上一个方法中的catch代码块中,如果这个方法中还没有catch模块,Java虚拟机将继续在方法的调用栈中向上传递控制直到找到能处理这个异常的catch模块。throw抛出异常语句的一般形式为:
throw new Exception("the program just throw an exception");
4.6.2 throws语句
throws关键字是用在方法声明中,用来列出从方法中发出的、非起源于Error或Runtime Exception中的任何异常(从RuntimeExeeption类型派生的异常通常是可以避免的类型,而从Error类型派生的异常通常与严重的系统问题有关)。能够主动引发异常的方法必须用throws来声明。一般包含一个throws子句的方法声明形式为:
type method_name(parameter_list) throws exception_list{}
其中exception_list是该方法可以引发的以逗号分隔的异常列表。
4.6.3 finally语句
finally关键字是紧跟在try/catch异常模块之后的模块。因为有时我们想执行一段代码,但在执行该段代码之前出现了异常,如果出现异常这段代码就不会被执行,但我们又想执行该段代码,所以就用到了finally关键字。使用finally关键字时,无论其前面的try语句和catch语句怎样执行以及是否执行,finally语句都必须执行一次。所以,我们把我们想执行的代码放在finally模块里就可以保证即使出现异常也能执行。
4.7 自定义异常类
虽然在Java的异常处理机制里面有很强大的异常处理类,但对于某些特殊异常我们还是要自己来处理的,所以我们就要自定义异常类。创建异常类的方法很简单,只要定义Exception的一个子类就可以实现。由于Exception继承自Throwable,因此自定义异常类可以获得Throwable类中定义的方法,当然也可以在自定义类中重载从Throwable类中继承的某些方法。
4.8 异常应用的其他问题
必须先catch较小的异常,再catch大的。
使用自定义的常一般有如下步骤:
a) 通过继承java.lang.Exception类声明自己的异常类。
b) 在方法适当的位置生成自定义异常的实例,并用throw语句抛出。
c) 在方法的声明部分用throws语句声明该方法可能抛出异常。
异常一致性:重写方法需要抛出与员方法所抛出异常类型一致异常或不抛出异常。
4.9 异常应用举例:
import java.io.*;
public class TestEx {
public static void main(String[] args) {
FileInputStream in = null;
try {
in = new FileInputStream("myfile.txt");
int b;
b = in.read();
while (b != -1) {
System.out.print((char) b);
b = in.read();
}
} catch (IOException e) {
System.out.println(e.getMessage());
/*
* } catch (FileNotFoundException e) { e.printStackTrace();
*/
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果:
myfile.txt (系统找不到指定的文件。)
Exception in thread "main" java.lang.NullPointerException
at TestEx.main(TestEx.java:20)