学到异常处理了,于是想记录下Java异常处理的细节,以增加对异常处理的印象。
Java常见的异常类之间的继承关系:
(仿李刚老师的《疯狂Java讲义》异常章节的图)
Java的异常被分为两大类:Checked异常(编译时出现异常)和Runtime(运行时异常)。
1、编译时被检测的异常,除了特殊子类RuntimeException体系的,只要是Exception和其子类都是。
这种问题一旦出现,希望在编译时就进行检测,让这种问题有对应的处理方式。
2、编译时不检测异常(运行时异常),就是Exception中的RuntimeException和其子类,这种问题的发生,让 功能无法继续,运算也无法进行,更多是因为调用的原因导致的。或者引发程序内部状态改变,导致异 常。这种问题一般不处理,直接编译通过,在运行时,调用者调用时引发异常从而程序强制停止,此时调用者即可对异常进行修正。
异常Demo演示:
public class First { private int num; public void change(String str) { int a = Integer.parseInt(str); this.num = a; } public static void main(String[] args) { First f = new First(); f.change("one"); } } /* 编译这段代码后,运行出现NumberFormatException异常,这是一个运行时异常 */增加一个自定义的异常处理类:
class MyException extends Exception //自定义一个异常类, { /*如果将MyException继承自RuntimeException,就没有后面的故事了,呵呵! *这样后,MyException就是一个运行时异常,从下面的叙述中, *你应该能看出运行时异常和编译时异常的区别吧 */ public MyException(){} public MyException(String msg) { super(msg); } } public class First { private int num; public void change(String str) { try { int a = Integer.parseInt(str); this.num = a; } catch(Exception e) { throw new MyException("You should pass a integer string."); //抛出自定义异常 } } public static void main(String[] args) { First f = new First(); f.change("one"); } } /* 编译这段代码后,出现错误: First.java:22: error: unreported exception MyException; must be caught or declared to be thrown throw new MyException("You should pass a integer string."); //?????????? ?? ^ 1 error */
"未报告的异常,必须被捕获或者声明",此处编译不能通过,对于自定义的异常类属于编译时异常,需要在函数在函数出进行声明,代码改成如下:
class MyException extends Exception //自定义一个异常类 { public MyException(){} public MyException(String msg) { super(msg); } } public class First { private int num; public void change(String str) throws MyException //在方法声明上抛出,是为了告诉调用者,你注意了,我有问题 { try { int a = Integer.parseInt(str); this.num = a; } catch(Exception e) { throw new MyException("You should pass a integer string."); //抛出自定义异常 } } public static void main(String[] args) { First f = new First(); f.change("one"); } } /* 编译这段代码后,出现错误: First.java:30: error: unreported exception MyException; must be caught or declared to be thrown f.change("one"); ^ 1 error */为什么还是不能编译通过呢?一开始在change()方法体内遇到throw new MyException("You should pass a integer string."); 准备抛出异常,可是change()方法没有显示声明这个异常,对于编译性的异常,需要显示进行声明,让JVM知道后续程序运行时该怎么处理。后来在change()方法声明了我的自定义异常:public void change(String str) throws MyException,所以change()方法中的MyException异常被抛到调用change()方法的main主函数中,所以出现了上面的错误,因而也需要在main主函数声明MyException。下面是正确代码:
class MyException extends Exception //自定义一个异常类 { public MyException(){} public MyException(String msg) { super(msg); } } public class First { private int num; public void change(String str) throws MyException { try { int a = Integer.parseInt(str); this.num = a; } catch(Exception e) { throw new MyException("You should pass a integer string."); //抛出自定义异常 } } public static void main(String[] args) throws MyException //这里抛出自定义异常,但我们在程序开发时,通常不这么做 { First f = new First(); f.change("one"); } } /** Exception in thread "main" MyException: You should pass a integer string. at First.change(First.java:22) at First.main(First.java:30) */编译、运行上面的代码后,最终的MyException异常被抛给JVM,JVM打印出异常跟踪栈。对于这样的异常,可以进行必要的try catch操作。如:
class MyException extends Exception //自定义一个异常类 { public MyException(){} public MyException(String msg) { super(msg); } } public class First { private int num; public void change(String str) throws MyException // 注:如果MyException是一个RuntimeException, 这里就不用声明抛出了 { try { int a = Integer.parseInt(str); this.num = a; } catch(Exception e) { throw new MyException("You should pass a integer string."); //抛出自定义异常 } } public static void main(String[] args) { First f = new First(); try { f.change("one"); } catch(MyException e) //直接捕获并处理了 { System.out.println("error: " + e.getMessage()); } } }再对比一个编译时异常的例子:
import java.io.IOException; import java.io.FileInputStream; public class Second { public void fileTest() { FileInputStream fis = null; try { fis = new FileInputStream("no-such-a-file.txt"); } catch(Exception e) { throw new IOException(); } } public static void main(String[] args) { Second f = new Second(); f.fileTest(); } }也会出现:
Second.java:14: error: unreported exception IOException; must be caught or declared to be thrown
throw new IOException();
^
1 error
IOException是编译时异常,这样的错误, 所以你还是得在方法体上声明IOException,对于RuntimeException是不需要声明的。See next:
import java.io.IOException; import java.io.FileInputStream; public class Second { public void fileTest() throws IOException { FileInputStream fis = null; try { fis = new FileInputStream("no-such-a-file.txt"); } catch(Exception e) { throw new IOException(); } } public static void main(String[] args) throws IOException { Second f = new Second(); f.fileTest(); } }
这样就不会在编译时出现情况了,这算是应该注意的一个小细节吧。
下面再来看一个RuntimeException不需要声明的例子:
class MyException3 extends RuntimeException { private String message; public MyException3() { } public MyException3(String mess) { message = mess; } public String getMessage() { return message; } } public class NotDeclareRuntimeExceptionTest { public static void runtimeExceptionTest1(int n) { //这里不用声名抛出的异常 MyException3 if (n == 1) { throw new MyException3(); } else { System.out.println("dd"); } } public static void main(String[] args) { System.out.println("ok"); } }
参考博客:
http://www.blogjava.net/fancydeepin/archive/2015/10/15/382508.html
http://blog.csdn.net/hguisu/article/details/6155636