Java——异常处理
Posted xxbbtt
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java——异常处理相关的知识,希望对你有一定的参考价值。
1、java提供的异常不可能预见所有的问题,所以需要自己定义异常类,必须从已有的异常类继承,最好选择意思相近的异常类继承。
class MyException extends Exception{} public class Tree1 { public static void f() throws MyException{ System.out.println("throws MyException from f()"); throw new MyException(); } public static void main (String[] args) { try { f(); }catch(MyException e){ System.out.println("caught it"); } } }
try块中的代码将被监控,catch将会接受来自try块的异常。这里的f()方法将会抛出一个 MyException类的异常,然后catch将会接收到这个异常,并输出caught it4
所以输出结果为:
throws MyException from f() caught it
可以为异常类定义一个接受字符串参数的构造器:
class MyException extends Exception{ public MyException() {} public MyException(String msg) { super(msg); } } public class Tree1 { public static void f() throws MyException{ System.out.println("throws MyException from f()"); throw new MyException(); } public static void main (String[] args) { try { f(); }catch(MyException e){ e.printStackTrace(System.out); } } }
这样的输出是:
throws MyException from f() MyException at Tree1.f(Tree1.java:11) at Tree1.main(Tree1.java:16)
在异常类的定义中的第二个构造器中使用了super关键字明确调用了其基类构造器,它接受一个字符串作为参数。
在异常处理程序中,调用了Throwable类声明的printStackTrace()方法,就像输出中看到的这样,它将会打印“从方法调用处直到异常抛出处” 的方法调用序列,这里信息发送到了System.out,如果使用默认的e.printStackTrace();则信息将被输出到标准错误流。
2、Exception类型的方法
class MyException extends Exception{ public MyException() {} public MyException(String msg) { super(msg); } } class MySecondException extends Exception{ public MySecondException() {} public MySecondException(String msg) { super(msg); } } public class Tree1 { public static void f() throws MyException { System.out.println("throws MyException from f()"); throw new MyException("name"); } public static void g() throws MySecondException { System.out.println("throws MySecondException from g()"); throw new MySecondException("name2"); } public static void main (String[] args){ try { f(); // g(); }catch(Exception e){ System.out.println(e.getMessage()); System.out.println(e); System.out.println(e.getLocalizedMessage()); } } }
这里定义了两个继承自Exception的异常类,分别是MyException、MySecondException,由两个方法f()、g()抛出,如果在try块中只有f();,输出结果为:
throws MyException from f() name MyException: name name
Throwable类的getMessage()方法返回的是Exception的详细消息字符串,就是抛出这个异常时候传入的字符串,
而getLocalizedMessage()方法返回的是 Exception的本地化描述。
toString()方法返回 此对象的类的 name ": "(冒号和一个空格)
然后如果把上面代码g();的前面的//删掉,就是try块中将运行f()和g()两个方法,输出结果为:
throws MyException from f() name MyException: name name
和刚才一样这是因为catch接收到异常后就会结束try块中的程序运行,所以g()方法并没有被运行,所以如果先运行g()的结果就是:
throws MySecondException from g() name2 MySecondException: name2 name2
3、栈轨迹
public class Tree1 { public static void f(){ try { throw new Exception(); }catch(Exception e){ e.printStackTrace(); } } public static void g() {f();} public static void h() {g();} public static void main (String[] args){ f(); g(); h(); } }
输出结果为:
java.lang.Exception at Tree1.f(Tree1.java:17) at Tree1.main(Tree1.java:27) java.lang.Exception at Tree1.f(Tree1.java:17) at Tree1.g(Tree1.java:23) at Tree1.main(Tree1.java:28) java.lang.Exception at Tree1.f(Tree1.java:17) at Tree1.g(Tree1.java:23) at Tree1.h(Tree1.java:24) at Tree1.main(Tree1.java:29)
这里的调用的printStackTrace(),是Throwable类的方法,这个方法会将Throwable对象的栈轨迹信息打印到标准错误输出流上,第一行是异常类的tostring()方法输出的内容,后面几行的内容都是之前通过fillInStackTrace()方法保存的内容。
java.lang.Exception at Tree1.f(Tree1.java:17) at Tree1.main(Tree1.java:27)
在这个例子中,在方法f()中抛出异常,在main方法中捕获异常,并且打印栈轨迹信息。因此,输出依次展示了f—>main的过程。还打印了抛出错误,捕获错误的行数、类的名字。
java.lang.Exception at Tree1.f(Tree1.java:17) at Tree1.g(Tree1.java:23) at Tree1.main(Tree1.java:28)
这里就是在方法f()中抛出异常,方法g()中调用了f(),然后和上一个一样了,第三个也同样。
public class Tree1 { public static void f(){ try { throw new Exception(); }catch(Exception e){ for(StackTraceElement ste: e.getStackTrace()) { System.out.println(ste); } } } public static void g() {f();} public static void h() {g();} public static void main (String[] args){ f(); System.out.println("------------------"); g(); System.out.println("------------------"); h(); } }
这个例子中调用了getStackTrace()方法,这个方法返回StackTraceElement类的一个对象。其输出内容为:
Tree1.f(Tree1.java:17) Tree1.main(Tree1.java:30) ------------------ Tree1.f(Tree1.java:17) Tree1.g(Tree1.java:26) Tree1.main(Tree1.java:32) ------------------ Tree1.f(Tree1.java:17) Tree1.g(Tree1.java:26) Tree1.h(Tree1.java:27) Tree1.main(Tree1.java:34)
如果这样使用:
public class Tree1 { public static void f(){ try { throw new Exception(); }catch(Exception e){ for(StackTraceElement ste: e.getStackTrace()) { System.out.print(ste.getMethodName() + " " ); System.out.println(ste.getLineNumber()); } } } public static void g() {f();} public static void h() {g();} public static void main (String[] args){ f(); System.out.println("------------------"); g(); System.out.println("------------------"); h(); } }
调用StackTraceElement中的方法getMethodName()和getLineNumber()就可以值获取栈轨迹中的方法 和行:
f 17 main 30 ------------------ f 17 g 26 main 32 ------------------ f 17 g 26 h 27 main 34
所以,其实StackTraceElement是一个栈轨迹元素的数组。将这些栈轨迹元素保存在一个数组中。每个元素对应栈的一个栈帧。数组的第一个元素保存的是栈顶元素,也就是上面的f。最后一个元素保存的栈底元素,也就是main。
public class Tree1 { public static void f() throws Exception{ throw new Exception(); } public static void g() throws Exception { try { f(); }catch(Exception e){ e.printStackTrace(); throw e; } } public static void main (String[] args){ try { g(); }catch(Exception e){ e.printStackTrace(); } } }
4、重新抛出异常
这里f()函数中抛出一个异常,然后g()方法中捕获了这个异常并打印异常栈轨迹Stack Trace,然后又再抛出了刚刚的异常,mai方法中捕获 了这个异常并打印异常栈轨迹Stack Trace,所以结果为:
java.lang.Exception at Tree1.f(Tree1.java:16) at Tree1.g(Tree1.java:21) at Tree1.main(Tree1.java:30) java.lang.Exception at Tree1.f(Tree1.java:16) at Tree1.g(Tree1.java:21) at Tree1.main(Tree1.java:30)
也就是说,捕获到异常又立即抛出,在上级方法调用中再次捕获这个异常,打印的栈轨迹信息是一样的。额,其实只看代码也知道,因为这里只是把刚刚异常e又抛出一次,
public class Tree1 { public static void f() throws Exception{ throw new Exception(); } public static void g() throws Exception { try { f(); }catch(Exception e){ e.printStackTrace(); throw (Exception)e.fillInStackTrace(); } } public static void main (String[] args){ try { g(); }catch(Exception e){ e.printStackTrace(); } } }
throw (Exception)e.fillInStackTrace();
这一行调用了Exception的fillInStackTrace()方法,首先要知道其实这个方法并不是来自于Exception类。Exception类本身除了定义了几个构造器之外,所有的方法都是从其父类继承过来的。而和异常相关的方法都是从java.lang.Throwable类继承过来的,所以其实fillInStackTrace()是Throwable类的方法,然后fillInStackTrace()方法就是将当前线程当前状态下的轨迹栈的状态保存进Throwabe中,就是更新的意思。
public Throwable fillInStackTrace()
这是这个方法的原型所以它的返回值是一个Throwable类对象,所以使用它更新的时候需要强制类型转换。
throw (Exception)e.fillInStackTrace();
所以输出内容为:
java.lang.Exception at Tree1.f(Tree1.java:16) at Tree1.g(Tree1.java:21) at Tree1.main(Tree1.java:30) java.lang.Exception at Tree1.g(Tree1.java:24) at Tree1.main(Tree1.java:30)
这次第二个打印的栈轨迹信息就没有f了。
5、异常链
class MyException1 extends Exception{} class MyException2 extends Exception{} public class Tree1 { public static void f() throws MyException1{ throw new MyException1(); } public static void g() throws MyException2{ try { f(); } catch (MyException1 e) { e.printStackTrace(); throw new MyException2(); } } public static void main (String[] args){ try { g(); }catch(Exception e){ e.printStackTrace(); } } }
这里定义了两个异常类,f()方法抛出了MyException1,g()方法捕获了这个异常并打印了异常的栈轨链,然后抛出了另一个异常MyException2也打印了异常的栈轨链,所以输出结果为:
MyException1 at Tree1.f(Tree1.java:16) at Tree1.g(Tree1.java:21) at Tree1.main(Tree1.java:31) MyException2 at Tree1.g(Tree1.java:24) at Tree1.main(Tree1.java:31)
这没什么毛病,但是常常想要在捕获一个异常后抛出另一个异常,并且希望把原始异常的信息保存下来,这就需要将原始异常的信息包装在新的异常中,这被称为异常链
class MyException1 extends Exception{} class MyException2 extends Exception{ MyException2(Throwable throwable){ super(throwable); } MyException2(){ super(); } } public class Tree1 { public static void f() throws MyException1{ throw new MyException1(); } public static void g() throws MyException2{ try { f(); } catch (MyException1 e) { e.printStackTrace(); throw new MyException2(e); } } public static void main (String[] args){ try { g(); }catch(Exception e){ e.printStackTrace(); } } }
这样的输出结果就是:
MyException1 at Tree1.f(Tree1.java:16) at Tree1.g(Tree1.java:21) at Tree1.main(Tree1.java:31) MyException2: MyException1 at Tree1.g(Tree1.java:24) at Tree1.main(Tree1.java:31) Caused by: MyException1 at Tree1.f(Tree1.java:16) at Tree1.g(Tree1.java:21) ... 1 more
这样的定义:
public class MyException2 extends Exception{ //定义异常的原因 public MyException2(String message){ super(message); } //定义异常原因,并携带原始的异常 public MyException2(String message,Throwable cause){ super(message,cause); } //保留原始异常信息 publicMyException2(Throwable cause){ super(cause); } }
就能将原始异常传递给新异常
或是:
class MyException1 extends Exception{ } class MyException2 extends Exception{ MyException2(Throwable throwable){ super(throwable); } MyException2(){ super(); } } class MyException3 extends Exception{ MyException3(Throwable throwable){ super(throwable); } MyException3(){ super(); } } public class Tree1 { public static void f() throws MyException1{ throw new MyException1(); } public static void g() throws MyException2{ try { f(); } catch (MyException1 e) { // e.printStackTrace(); throw new MyException2(e); } } public static void h() throws MyException3{ try { g(); } catch (MyException2 e) { // e.printStackTrace(); throw new MyException3(e); } } public static void main (String[] args){ try { h(); }catch(Exception e){ e.printStackTrace(); } } }
这里值输出了最后一个异常的栈轨迹
MyException3: MyException2: MyException1 at Tree1.h(Tree1.java:44) at Tree1.main(Tree1.java:51) Caused by: MyException2: MyException1 at Tree1.g(Tree1.java:35) at Tree1.h(Tree1.java:41) ... 1 more Caused by: MyException1 at Tree1.f(Tree1.java:27) at Tree1.g(Tree1.java:32) ... 2 more
其中还包括了MyException1和MyException2 的信息
Exception
以上是关于Java——异常处理的主要内容,如果未能解决你的问题,请参考以下文章
java.util.MissingResourceException: Can't find bundle for base name init, locale zh_CN问题的处理(代码片段
java.lang.NullPointerException: Attempt to invoke virtual method ‘int android.database.sqlite异常(代码片段
PCL异常处理:pcl 1.8.13rdpartyoostincludeoost-1_64oost ypeofmsvc ypeof_impl.hpp(125): error(代码片段