Java异常处理
1.捕获异常
当我们程序遇到异常时,程序会被终止。
如果我们不希望程序被终止怎么办,很简单,可以把有可能发生异常的代码块放进try语句里面,然后在catch语句里面捕获可能发生的异常类型。
try-catch语句:要捕获所有可能发生的异常类型,同一种类型的异常只用一个catch就可以了。
try{ //可能发生异常的代码块 } catch(Exception1 e){ 捕获Exception1类型的异常 } catch(Exception2 e){ 捕获Exception2类型的异常 } catch(Exception3 e){ 捕获Exception3类型的异常 } //etc...
PS:try语句和catch语句都必须加花括号({}),即使里面只有一条语句。try语句不能单独存在,后面必须接catch语句或者finally语句
try-finally语句:希望程序发生异常时,仍然执行某一段代码时可以用try-finally语句
try{ //可能发生异常的代码块 } finally{ //不管try中代码块中是否产生异常,finally中的代码总是被执行 }
另外还有try-catch-finally语句,它相当于上面两种语句的结合。此时同样是在catch语句中捕获异常,不管try中语句是否产生异常或者异常是否被捕获,finally语句总是被执行。
2.抛出异常
2.1throws抛出异常
用throws声明抛出异常时,表示将异常交给上一级调用者处理。throws抛出的是异常类,放在方法签名的后面。
void play(){ try { pain(); } catch (Throwable e) { e.printStackTrace();//打印异常跟踪信息 } } void pain()throws Throwable{ //产生异常代码 }
play()方法调用pain()方法,pain()方法产生异常,但是没有处理,向上抛给调用它的方法,所以在play()方法中要处理这个异常。
那么如果在main()方法中有可能异常,我们也用throws抛出异常会怎么样?
public class MyException { public static void main(String[] args) throws Throwable{ String str="hello"; str.charAt(10); } }
输出结果:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 10
at java.lang.String.charAt(Unknown Source)
at com.t.MyException.main(MyException.java:6)
我们清楚地看到程序报错了。这是因为此时main()方法没有上级调用者,产生的异常会交给Java编译器或虚拟机处理。非运行时异常编译器处理,不让程序编译通过。运行时异常Java虚拟机处理,JVM对异常的对异常的处理方法是,打印异常的跟踪栈信息,并终止程序的运行。
PS:如果上一级调用者,没有处理被调用抛出的异常时,程序也会被终止。
2.2throw抛出异常
用throw抛出异常,抛出的不是一个异常类,而是一个异常实例。在程序中的含义是自动产生一个异常。public class MyException { public static void main(String[] args) { throw new StringIndexOutOfBoundsException(); } }
程序输出结果是:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException
at com.t.MyException.main(MyException.java:5)
这说明此时程序产生了一个StringIndexOutOfBoundsException的异常。
3.异常丢失
下面我们来看看这个程序。
public class MyException { public void play() throws Throwable{ try{ String str="lavor_zl"; str.charAt(10); pain(); }catch(StringIndexOutOfBoundsException e){ throw new StringIndexOutOfBoundsException(); }catch(ArrayIndexOutOfBoundsException e){ throw new ArrayIndexOutOfBoundsException(); } } public void pain() throws ArrayIndexOutOfBoundsException{ try{ int[] array=new int[10]; array[12]=2014; }catch(ArrayIndexOutOfBoundsException e){ throw new ArrayIndexOutOfBoundsException(); } } public static void main(String[] args) { MyException my=new MyException(); try { my.play(); } catch (Throwable e) { e.printStackTrace(); } } }
输出结果:
java.lang.StringIndexOutOfBoundsException
at com.t.MyException.play(MyException.java:10)
at com.t.MyException.main(MyException.java:26)
调用play()方法明明会产生两个异常,为什么输出结果只打印了一个异常的跟踪信息。其实,只要把前面讲的弄清楚了,就知道为什么了。
我现在来分析一下原因。当我们运行到"str.charAt(10);"这行代码的时候,catch捕获到一个StringIndexOutOfBoundsException异常,同时抛出一个StringIndexOutOfBoundsException异常的实例,这时程序本应该被终止,因为play()方法中没有捕获这个自动产生的异常。
但是由于play()方法用了throws Throwable抛出异常,所以程序没有被终止,而是把异常交给play()方法的上级调用者main()方法处理。虽然程序没有被终止,但是由于play()方法产生了异常没有处理,而是抛给了它的上级调用者main()方法。那么产生异常时,play()方法中本该在异常之后执行的代码就不会被执行了。
上面那个程序弄清楚了后,这个程序也会很容易明白,是一个典型的异常丢失的情况。
public class MyException { public void play() throws Throwable{ try{ pain(); }catch(ArrayIndexOutOfBoundsException e){ StringIndexOutOfBoundsException c=new StringIndexOutOfBoundsException(); throw c; } } public void pain() throws ArrayIndexOutOfBoundsException{ try{ int[] array=new int[10]; array[12]=2014; }catch(ArrayIndexOutOfBoundsException e){ throw new ArrayIndexOutOfBoundsException(); } } public static void main(String[] args) { MyException my=new MyException(); try { my.play(); } catch (Throwable e) { e.printStackTrace(); } } }
输出结果:
java.lang.StringIndexOutOfBoundsException
at com.t.MyException.play(MyException.java:8)
at com.t.MyException.main(MyException.java:23)
结果只打印了一个异常的跟踪信息,这是一个典型的异常丢失的情况,我们经常用它来引出异常链,因为它和异常连最接近。
4.异常链
我们来看看下面这个程序吧,这个程序用到了异常链。
public class MyException { public void play() throws Throwable{ try{ pain(); }catch(ArrayIndexOutOfBoundsException e){ StringIndexOutOfBoundsException c=new StringIndexOutOfBoundsException(); c.initCause(e);//异常链 throw c; } } public void pain() throws ArrayIndexOutOfBoundsException{ try{ int[] array=new int[10]; array[12]=2014; }catch(ArrayIndexOutOfBoundsException e){ throw new ArrayIndexOutOfBoundsException(); } } public static void main(String[] args) { MyException my=new MyException(); try { my.play(); } catch (Throwable e) { e.printStackTrace(); } } }
输出结果:
java.lang.StringIndexOutOfBoundsException
at com.t.MyException.play(MyException.java:8)
at com.t.MyException.main(MyException.java:24)
Caused by: java.lang.ArrayIndexOutOfBoundsException
at com.t.MyException.pain(MyException.java:18)
at com.t.MyException.play(MyException.java:6)
... 1 more
从输出结果可以看到此时打印了两个异常的跟踪信息,这是因为用到了异常链的原因。
我们还发现这个程序仅仅只比上面的程序多一行“c.initCause(e);”,这就是异常链的用法,用原始异常来初始化引起现在异常的原因。
异常链的特性是所有异常均具备的,因为这个initCause()方法是从Throwable继承的。
5.异常的分类
Throwable类是所有异常的父类。
Throwable有两个子类,ERROR(错误)和Exception。
Exception下面有非运行时异常(编译异常)和运行时异常(RuntimeException)。
非运行时异常需要捕获,不然编译器不让通过。运行时异常可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
6.自定义异常
我们自定义普通异常时应该继承Exception,定义运行时异常要继承RuntimeException。
/* 自定义异常举例 */ class MyException extends Exception{ public MyException() { super(); } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。