一、异常的捕获和处理
1)实现一个可以抛出异常的方法:
package com.hpe.exception;
public class TestEx2 {
public static void main(String[] args) {
TestEx2 te = new TestEx2();
te.m(0);
}
void m(int i) throws ArithmeticException {
if(i == 0) {
throw new ArithmeticException("除数为0");
}
}
}
运行结果:
Exception in thread "main" java.lang.ArithmeticException: 除数为0
at com.hpe.exception.TestEx2.m(TestEx2.java:12)
at com.hpe.exception.TestEx2.main(TestEx2.java:7)
总结:
这个异常属于RuntimeException,即使不捕获,程序也是可以运行起来的,只是运行时会出异常,而且程序会停止运行。
2)我们也可以选择捕获这个异常:
package com.hpe.exception;
public class TestEx2 {
public static void main(String[] args) {
try {
new TestEx2().m(0);
} catch (ArithmeticException e) {
System.out.println(e.getMessage());
}
}
void m(int i) throws ArithmeticException {
if (i == 0) {
throw new ArithmeticException("出错啦,除数为0");
}
}
}
运行结果:
出错啦,除数为0
总结:
a、使用我们自己写的catch语句来捕获异常可以使提示变得友好,而且程序可以继续往下执行。
b、异常类都有构造方法,可以传入字符串以表示该异常对象的一些信息,通过getMassage()方法可以返回这些字符串信息。
3)对于一些非RuntimeException异常,如果不捕获或抛出,编译器会提示错误,程序是无法运行的。
package com.hpe.exception;
import java.io.FileInputStream;
public class TestEx3 {
public static void main(String[] args) {
FileInputStream in = new FileInputStream("myfile.txt");
}
}
无法通过编译。
4)下面开始介绍必须要捕获或抛出的非RuntimeException。
可以使用多个catch语句捕获不同的异常
package com.hpe.exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TestEx3 {
public static void main(String[] args) {
FileInputStream in = null;
try {
in = new FileInputStream("myfile.txt");
int b = in.read();
while(b != -1) {
System.out.println((char)b);
b = in.read();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5)f1()方法处理不了的异常可以抛给调用f1()方法的地方去处理。
package com.hpe.exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TestEx4 {
public static void main(String[] args) {
new TestEx4().f2();
}
void f1() throws FileNotFoundException, IOException {
FileInputStream in = null;
in = new FileInputStream("myfile.txt");
int b = in.read();
while(b != -1) {
System.out.println((char)b);
b = in.read();
}
}
void f2() {
try {
f1();
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
e.printStackTrace();
}
}
}
6)异常可以一直往方法外抛。
package com.hpe.exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class TestEx4 {
public static void main(String[] args) {
try {
new TestEx4().f2();
} catch (FileNotFoundException e) {
System.out.println("捕获到FileNotFoundException!");
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
void f1() throws FileNotFoundException, IOException {
FileInputStream in = null;
in = new FileInputStream("myfile.txt");
int b = in.read();
while(b != -1) {
System.out.println((char)b);
b = in.read();
}
}
void f2() throws IOException {
f1();
}
}
运行结果:
捕获到FileNotFoundException!
总结:
a、如果所抛出的多个异常中有一个异常类是其他异常类的父类,可以只抛这个父类异常,即就算不显式地写出要抛子类异常,子类异常也会被抛出,因为子类异常都属于父类异常的一种。在try-catch的时候,再去catch子类异常,这样也是可以的,但不推荐这种写法,因为如果简化了所抛出的异常种类,甚至直接throws Exception,在对所调用的方法进行捕获的时候,根本不知道会抛出哪种异常,不便于写分门别类的多分支catch语句,所以建议将可以抛出的异常全部写全,而不是只写一个父类异常了事。
b、main方法也可以将异常往外抛,抛给Java虚拟机。
5)总结:
a、try代码段包含可能产生异常的代码。
b、try代码段后跟有一个或多个catch代码段。
c、每个catch代码段声明其能处理的一种特定类型的异常,并提供处理的方法。
d、每当异常发生时,程序会终止当前的流程,根据所获取异常的类型去执行相应的catch代码段。
e、如果没有异常产生,所有的catch代码段都被略过不执行。
f、finally段的代码无论是否发生异常都会被执行。
7)try语句
a、try{...}语句指定了一段代码,该段代码是可能会发生异常的代码。
b、在执行过程中,该段代码可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句要分别对这些异常做相应的处理。
c、如果没有异常产生,所有的catch代码段都被略过
8)catch语句
a、在catch语句块中是对异常进行处理的代码,每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。
b、在catch语句中声明的异常对象封装了异常事件发生的信息,在catch语句块中可以使用异常对象的一些方法获取异常的相关信息。
3)如:
getMessage() //用来得到有关异常事件的信息。
printStackTrace()//用来跟踪异常事件发生时执行堆栈的内容
8)finally语句
a、finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分以前,能够对程序得状态做统一的管理。
b、无论try所指定的程序块中是否抛出异常,finally指定的代码都要被执行。
c、通常在finally语句中可以进行资源的清除工作。
9)需要注意的一些细节:
package com.hpe.exception;
public class TestEx5 {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
try {
System.out.println(arr[5]);
} catch (Exception e) {
System.out.println("有异常发生了");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组下标越界了");
}
}
}
编译器会报错,在一个try-catch语句中,父类异常的捕获语句不可以写在子类异常捕获语句的上面。
把握一个原则:在捕获异常的时候,要先逮小的,再逮大的。