1. java异常机制概述
1.1 继承体系
Error: 表示错误,一般指JVM相关的不可修复的错误,如:系统崩溃,内存溢出,JVM错误等。由JVM抛出,我们不需要进行处理
Exception: 表示异常,指程序中出现不正常的情况,该问题可以修复处理。
RuntimeException: 运行时异常。在编译时期,可以不处理(抛出或捕获处理),编译会通过。但在运行时期可以会产生的异常。常见的如:NullPointerException, ArithmeticException等
CheckedException: 编译时异常。在编译时期会进行检查,如果没有进行处理(抛出或捕获处理),编译不会通过。常见的如:IOException, SQLException等
public class ExceptionTest {
public void testNullPointerException() {
throw new NullPointerException();//编译通过
}
public void testCheckedException() {
try {
throw new IOException();//必须进行处理,否则编译不通过
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
1.2 自定义异常
class MyException extends Exception{}
class MyRuntimeException extends RuntimeException{}
public class ExceptionTest {
public void testMyException() {
try {
throw new MyException();
} catch (MyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void testMyRuntimeException() {
throw new MyRuntimeException();
}
}
当我们自定义的异常MyException直接继承父类Exception时,也类似于受查异常,必须在编译期进行处理,否则编译不通过。当我们自定义的异常MyRuntimeException直接继承父类RuntimeException时,跟RuntimeException一样,不需要在编译器处理也可以编译通过。
2. 异常处理机制
2.1 try-catch
2.1.1 语法结构
try {
//可能发生异常的代码(监控区域)
} catch (ExceptionType1 e1) {
//当监控区域产生ExceptionType1 类型或其子类的异常时,执行的代码块
} catch (ExceptionType2 e2) {
//当监控区域产生ExceptionType2 类型或其子类的异常时,执行的代码块
} ...
2.2.2 异常匹配原则
如果抛出的异常对象属于catch异常的类型或其子类时,则认为生成的异常对象与其异常类型匹配;
当抛出的异常类型同时与多个catch异常类型匹配时,应该按照代码顺序执行,且一旦被一块catch捕获后,就不能被其他catch捕获了。
public class ExceptionTest {
public static void main(String[] args) {
try {
int a = 1/0;
} catch (ArithmeticException e) {
System.out.println("被ArithmeticException捕获...");
} catch (Exception e) {
System.out.println("被Exception捕获...");
}
System.out.println("end...");
}
}
结果:
被ArithmeticException捕获...
end...
注意:1.我们一般将子类的Exception放在前面,否则该处代码将永远不会被执行(这种现象叫做异常屏蔽)
2.一旦try代码块中未抛出异常,或抛出异常后被捕获处理且未再抛出异常,则,try-catch代码块后的代码将会继续执行
2.2 try-catch-finally
2.2.1 语法结构
try {
//可能发生异常的代码(监控区域)
} catch (ExceptionType1 e1) {
//当监控区域产生ExceptionType1 类型或其子类的异常时,执行的代码块
} catch (ExceptionType2 e2) {
//当监控区域产生ExceptionType2 类型或其子类的异常时,执行的代码块
}
......
finally {
//最终执行的代码块
}
2.2.2 finally代码块:
2.2.2.1 无论是否捕获处理了异常,finally代码块一般都会执行
2.2.2.2 如果try或catch代码块中有return语句,则finally代码块会在return语句执行前执行
2.2.2.3 在几类特殊情况下,finally语句不会被执行:
在finally语句中发生异常,在语句执行过程中退出了jvm(如:调用System.exit(0)),程序所在的线程死亡等
2.2.2.4 在方法中如果有返回值和没有返回值,程序调用结果会不同,看下面的实例:
public class MyExceptionTest {
@Test
public void test() {
try {
int a = testThrowOrReturn();
System.out.println(a);
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
}
}
private int testThrowOrReturn() throws Exception {
// TODO Auto-generated method stub
try {
System.out.println("try代码块");
int a = 1/0;
return a;
} catch (Exception e) {
System.out.println("catch代码块");
throw new Exception("catch中异常");
} finally {
System.out.println("finally代码块");
return -1;
}
}
}
执行结果:
try代码块
catch代码块
finally代码块
-1
try语句中1/0时抛出异常,被catch语句捕获,打印了catch代码块。之后就执行了finally代码块,返回-1。即catch语句中throw
new Exception代码并没有执行。如果执行了会被test方法捕获并打印出来。我们从结果看出,并没有打印e.getMessage().
再看下面这个例子:
public class MyExceptionTest {
@Test
public void test() {
try {
testThrow();
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
}
}
private void testThrow() throws Exception{
try {
System.out.println("try代码块");
int a = 1/0;
} catch (Exception e) {
System.out.println("catch代码块");
throw new Exception("catch中异常");
} finally {
System.out.println("finally代码块");
}
}
}
运行结果:
try代码块
catch代码块
finally代码块
catch中异常
catch代码块中的异常有被抛出。在finally代码块执行完成之后(没有返回值),又将atch代码块中的异常抛出。
3. 抛出异常
3.1 throw
3.1.1 运用于方法内部,表示抛出一个异常对象,并结束执行当前代码块
3.2 throws
3.2.1 运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理该异常(当然方法调用者也可以选择不处理,但必须继续抛出,如果选择抛出,则最终将交给jvm)
4. 最后网上留了一道例题(例题)
package com.tca.thinkInJava.chap12.test;
public class ExceptionDemo {
public ExceptionDemo() {
}
boolean testEx() throws Exception {
boolean ret = true;
try {
ret = testEx1();
} catch (Exception e) {
System.out.println("testEx, catch exception");
ret = false;
throw e;
} finally {
System.out.println("testEx, finally; return value=" + ret);
return ret;
}
}
boolean testEx1() throws Exception {
boolean ret = true;
try {
ret = testEx2();
if (!ret) {
return false;
}
System.out.println("testEx1, at the end of try");
return ret;
} catch (Exception e) {
System.out.println("testEx1, catch exception");
ret = false;
throw e;
} finally {
System.out.println("testEx1, finally; return value=" + ret);
return ret;
}
}
boolean testEx2() throws Exception {
boolean ret = true;
try {
int b = 12;
int c;
for (int i = 2; i >= -2; i--) {
c = b / i;
System.out.println("i=" + i);
}
return true;
} catch (Exception e) {
System.out.println("testEx2, catch exception");
ret = false;
throw e;
} finally {
System.out.println("testEx2, finally; return value=" + ret);
return ret;
}
}
public static void main(String[] args) {
ExceptionDemo testException = new ExceptionDemo();
try {
testException.testEx();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
i=2
i=1
testEx2, catch exception
testEx2, finally; return value=false
testEx1, finally; return value=false
testEx, finally; return value=false