3.1、 try、 catch 和 finally
异常的捕获和处理需要采用 try 和 catch 来处理,具体格式如下:
try {
}catch(OneException e) {
}catch(TwoException e) {
}finally {
}
try 中包含了可能产生异常的代码
try 后面是 catch, catch 可以有一个或多个, catch 中是需要捕获的异常
当 try 中的代码出现异常时,出现异常下面的代码不会执行,马上会跳转到相应的 catch语句块中,如果没有异常不会跳转到 catch 中。
finally 表示,不管是出现异常,还是没有出现异常, finally 里的代码都执行, finally 和catch 可以分开使用,但 finally 必须和 try 一块使用,如下格式使用 finally 也是正确的。
public class ExceptionTest {
public static void main(String[] args) {
int i1 = 100;
int i2 = 0;
// try 里是出现异常的代码
// 不出现异常的代码最好不要放到 try 作用
try {
// 当出现被 0 除异常,程序流程会执行到“catch(ArithmeticException ae)”语句
// 被 0 除表达式以下的语句永远不会执行
int i3 = i1 / i2;
// 永远不会执行
System.out.println(i3);
// 采用 catch 可以拦截异常
// ae 代表了一个 ArithmeticException 类型的局部变量
// 采用 ae 主要是来接收 java 异常体系给我们 new 的 ArithmeticException 对象
// 采用 ae 可以拿到更详细的异常信息
} catch (ArithmeticException ae) {
System.out.println("被 0 除了");
}
}
}
3.2、 getMessage 和 printStackTrace()
如何取得异常对象的具体信息,常用的方法主要有两种:
取得异常描述信息: getMessage()
取得异常的堆栈信息(比较适合于程序调试阶段): printStackTrace();
public class ExceptionTest {
public static void main(String[] args) {
int i1 = 100;
int i2 = 0;
try {
int i3 = i1 / i2;
System.out.println(i3);
} catch (ArithmeticException ae) {
// ae 是一个引用,它指向了堆中的 ArithmeticException
// 通过 getMessage 可以得到异常的描述信息
System.out.println(ae.getMessage());
}
}
}
3.3、受控异常
受控异常必须处理,否则无法编译通过!
public class ExceptionTest {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("test.txt");
} catch (FileNotFoundException e) {//此异常为受控异常,必须处理
e.printStackTrace();
}
}
}
3.4、 finally 关键字
finally 在任何情况下都会执行,通常在 finally 里关闭资源
public class ExceptionTest {
public static void main(String[] args) {
// 因为 fis 的作用域问题,必须放到 try 语句块外,局部变量必须给初始值
// 因为是对象赋值为 null
FileInputStream fis = null;
try {
fis = new FileInputStream("E:\\test.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
System.out.println("-------before fis.close--------");
// 放到 finally 中的语句,程序出现任何问题都会被执行
// 所以 finally 中一般放置一些需要及时释放的资源
fis.close();
System.out.println("-------after fis.close--------");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
深入 finally(1):
public class ExceptionTest {
public static void main(String[] args) {
int i1 = 100;
int i2 = 10;
try {
int i3 = i1 / i2;
System.out.println(i3);
return;
} catch (ArithmeticException ae) {
ae.printStackTrace();
} finally {
// 会执行 finally
System.out.println("----------finally---------");
}
}
}
深入 finally(2):
public class ExceptionTest {
public static void main(String[] args) {
int i1 = 100;
int i2 = 10;
try {
int i3 = i1 / i2;
System.out.println(i3);
// return;
System.exit(-1); // java 虚拟机退出
} catch (ArithmeticException ae) {
ae.printStackTrace();
} finally {
// 只有 java 虚拟机退出不会执行 finally
// 其他任何情况下都会执行 finally
System.out.println("----------finally---------");
}
}
}
深入 finally(3):
public class ExceptionTest {
public static void main(String[] args) {
int r = method1();
// 输出为: 10
System.out.println(r);
}
private static int method1() {
int a = 10;
try {
return a;
} finally {
a = 100;
}
}
}
深入 finally(4):
public class ExceptionTest {
public static void main(String[] args) {
int r = method1();
// 输出为: 100
System.out.println(r);
}
private static int method1() {
int a = 10;
try {
a = 50;
} finally {
a = 100;
}
return a;
}
}
3.5、如何声明异常
在方法定义处采用 throws 声明异常, 如果声明的异常为受控异常,那么调用方法必须处理此异常。
(1)、声明受控异常
public class ExceptionTest {
public static void main(String[] args){
try {
readFile();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void readFile() throws FileNotFoundException, IOException { // 声明异常,声明后调用者必须处理
FileInputStream fis = null;
try {
fis = new FileInputStream("test.txt");
} finally {
fis.close();
}
}
}
(2)、声明非受控异常
public class ExceptionTest {
public static void main(String[] args) {
// 不需要使用 try...catch..,因为声明的是非受控异常
method1();
// 也可以拦截非受控异常
/* try {
method1();
} catch (ArithmeticException e) {
e.printStackTrace();
}*/
}
// 可以声明非受控异常
private static void method1() throws ArithmeticException {
int i1 = 100;
int i2 = 0;
int i3 = i1 / i2;
System.out.println(i3);
}
}
3.6、如何手动抛出异常
采用异常来处理参数非法
public class ExceptionTest {
public static void main(String[] args) {
try {
int ret = method1(1000, 10);
System.out.println(ret);
} catch (Exception iae) { // 可以采用 Exception 拦截所有的异常
System.out.println(iae.getMessage());
}
}
private static int method1(int value1, int value2) {
if (value2 == 0) {
手动抛出异常
throw new IllegalArgumentException("除数为 0");
}
if (!(value1 > 0 && value1 <= 100)) {
// 手动抛出异常
throw new IllegalArgumentException("被除数必须为 1~100 之间的数据");
}
int value3 = value1 / value2;
return value3;
}
}
throws 和 throw 的区别? throws 是声明异常, throw 是抛出异常
public class ExceptionTest {
public static void main(String[] args) {
try {
int ret = method1(1000, 10);
System.out.println(ret);
} catch (Exception iae) {
System.out.println(iae.getMessage());
}
}
private static int method1(int value1, int value2) {
try {
if (value2 == 0) {
手动抛出异常
throw new IllegalArgumentException("除数为 0");
// 加入如下语句编译出错, throw 相当于 return 语句
// System.out.println("----------test111-----------");
}
if (!(value1 > 0 && value1 <= 100)) {
// 手动抛出异常
throw new IllegalArgumentException("被除数必须为 1~100 之间的数据");
}
int value3 = value1 / value2;
return value3;
} finally {
// throw 虽然类似 return 语句,但 finally 会执行的
System.out.println("-----------finally------------");
}
}
}
3.7、异常的捕获顺序
异常的捕获顺序应该是:从小到大
public class ExceptionTest {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("test.txt");
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
/* catch (FileNotFoundException e) {
e.printStackTrace();
}*/
// 将 IOException 放到前面,会出现编译问题
// 因为 IOException 是 FileNotFoundException 的父类,
// 所以截获了 IOException 异常后, IOException 的子异常
// 都不会执行到,所以再次截获 FileNotFoundException 没有任何意义
// 异常的截获一般按照由小到大的顺序,也就是先截获子异常,再截获父异常
}
}