java中的异常处理机制
异常是指程序运行时所发生的非正常情况或错误,java中使用异常能够降低错误处理代码的复杂度,如果不使用异常,就必须检查特定的错误,并在程序中的许多地方去处理它。
1.java的标准异常
Throwable这个java类被用来表示任何可以作为异常被抛出的类,Throwable对象可以分为两种类型,Error和Exception。
Error可以用来表示编译时和系统错误,表示程序在运行期间出现了非常严重的错误,并且该错误是不可恢复的,由于这属于JVM层次的严重错误,因此这种错误会导致程序终止执行。
Exception是可以被抛出的基本类型,表示可恢复的异常,是编译器可以捕捉到的,它包含两种类型,检查异常和运行时异常。检查异常是在程序中经常碰到的异常,比如最常见的IO异常和SQL异常,这种异常都发生在编译阶段,java编译器强制程序去捕获此类型的异常,即把可能会出现异常的代码块放在try块中,把对异常的处理放在catch块中。
运行时异常不同于检查异常,当出现这种异常时,会由JVM来处理,最常见的运行时异常包括NullPointerException(空指针异常),ClassCastException(类型转换异常),ArrayIndexOutOfBoundsException(数组越界异常),ArrayStoreException(数组存储异常),BufferOverFlowException(缓冲区溢出异常),ArithmeticException(算术异常)等。出现运行时异常后,系统会把异常一直往上层抛出,直到遇到处理代码为止,若没有处理块,则抛到最上层,如果是多线程,就用Thread.run()方法抛出,如果是单线程,就用main()方法抛出。抛出之后,如果是多线程,这个线程就退出了,如果是主线程,整个程序也就退出了。
2.抛出异常的三种方式
2.1 系统自动抛出异常
@Test public void test1(){ int a=8; int b=0; System.out.println(a/b); }
运行后抛出异常:java.lang.ArithmeticException: / by zero
2.2 throw
throw是语句抛出一个错误,一般是在代码块的内部,当程序出现某种逻辑错误时由程序员主动抛出某种特定类型的异常。在使用new创建了异常对象之后,此对象的引用将传递给throw。
@Test public void test2(){ String s="abc"; if(s.equals("abc")){ throw new NumberFormatException(); }else{ System.out.println(s); } }
运行后抛出异常:java.lang.NumberFormatException。
2.3 throws
当某个方法可能会抛出异常时,用throws声明可能抛出的异常,然后上交给它的方法程序处理。
public static void f() throws NumberFormatException{ System.out.println("try语句块先执行"); String s="abc"; System.out.println(Double.parseDouble(s)); } public static void main(String[] args){ try{ f(); }catch(NumberFormatException e){ System.err.println("非数据类型不能强制类型转换。"); } }
运行后输出:
try语句块先执行 非数据类型不能强制类型转换。
3.捕获异常
java程序在抛出异常后,首先使用new在堆上创建异常对象,然后当前的执行路径被终止,并且从当前环境中弹出对异常对象的引用,之后处理机制接管程序,并且开始寻找异常处理程序来继续执行程序。
如果在方法内部抛出异常,这个方法将在抛出异常的过程中结束,要是不希望方法就此结束,可以在方法内设置一个try块来捕获异常。抛出的异常必须在异常处理程序中得到处理,异常处理程序紧跟在try块之后,以关键字catch表示。异常处理程序的任务就是将程序从错误状态中恢复,以使程序要么换一种方式运行,要么继续运行下去。
import org.junit.Test; class Exception1 extends Exception{ } public class ExceptionTest { public int testFinally(){ try{ System.out.println("try执行"); throw new Exception1(); }catch(Exception1 e){ System.out.println("catch"); return 0; }finally{ System.out.println("execute finally");
return 1; } } @Test public void test(){ int result=testFinally(); System.out.println(result); } }
finally块的作用是为了保证无论出现什么情况,finally块里的代码一定会执行。 如果try-finally和catch-finally中都有return,那么finally块里的return语句将会覆盖别处的return语句,最终返回到调用者那里的都是finally中return值。(其他正常执行,但是return由finally中的return覆盖。)
程序运行结果:
try执行 catch execute finally 1
在使用异常处理时,还需注意java异常处理用到了多态的概念,如果在异常处理过程中,先捕获了基类,然后再捕获子类,那么捕获子类的代码块将永远不会被执行,因此在进行异常捕获时,正确的应该是先捕获子类,再捕获基类的异常信息。
try{
// }catch(SQLException e1){ // }catch(Exception e2){ // }