六、java 异常处理

一、JAVA异常的体系结构
   ① Error:Java虚拟机无法解决的严重问题;一般不编写正对性的代码处理;
   ② Exception:其他因为编程错误或偶然的外在因素导致的一般性问题;可以进行异常处理;处理完后不影响程序的运行;

 a.Exception又可以分为运行时异常和编译时异常;

 ①编译时异常(check):编译报错,要求必须处理,否则编译不通过;例如IOException、ClassNotFoundException

 ②运行时异常(unchecked  RuntimExceprion):一般不处理;例如:NullPointerExcepion(空指针异常),ArrayIndexOutOfBoundsException(数组越界异常),ClassCastExcetption(类转换异常),NumberFormateException...

二、异常处理的两种方式:

  ①不直接处理,往调用层抛出异常 throw + 异常类型;

  ②处理异常:try{}catch(){}finally{}

一下为异常处理的throw的方式:抛出异常,单元测试会报相应的NumberFormatException异常,无法执行到抛出异常后的语句;

1     @Test
2     public void testx() {
3             String str = "abc";
4             int num = Integer.parseInt(str);
5             System.out.println("hello -1");
6             throw new NumberFormatException();
7             //System.out.println("hello -2");
8     }

一下为异常处理的try catch的方式:单元测试通过,并且执行了System.out.println("hello -2");

 1     @Test
 2     public void test1() {
 3         String str = "abc";
 4         try {
 5             
 6             int num = Integer.parseInt(str);
 7             System.out.println("hello -1");
 8         }catch(NumberFormatException e) {//如果NumberFormatException换成时 NullPointerException则还是抛出异常
 9             System.out.println("出现数值转换异常了。。。。");
10             String mes = e.getMessage();
11             System.out.println(mes);//常用异常处理方式1
12             e.printStackTrace();//常用异常处理方式2
13             
14         }
15         System.out.println("hello -2");
16     }

 三、过程:

  过程一、“抛”;程序在正常执行过程中,一旦出现异常,就会在异常代码处生成一个对应异常的对象;并将此对象抛出;
 一旦抛出异常,其后面的代码不再执行;
  关于异常对象的产生,1,系统生成 的,2.手动生成一个异常对象并且抛出;throw;
  过程二:“抓”:可以理解为异常处理方式:

try catch finally的使用:
          try{
              //可能出现异常的代码
              }catch(异常类型1 变量名){
                     //处理异常方式1
              }catch(异常类型2 变量名){
                     //处理异常方式2
              }catch(异常类型3 变量名){
                     //处理异常方式3
              }
          ........
         finally{
             //一定会执行的代码
  }
  说明:
  1.finaly 是可选的
  2。使用try将肯出现的代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,
       根据此对象的类型,去catch中进行匹配
  3.一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常处理,一旦处理完成就跳出try-catch结构(在没有finally的情况),
 继续执行后面的代码;
  4.catch中的异常类型如果没有子父类关系,则谁声明在上面,谁声明在下,无所谓,
      catch中的异常类型如果满足子父类关系,则要求子类在上,父类在下,否则报错;
  5.常用的异常处理方式 a.String getMessage() ;b printStackTrace();
  6.在try中声明的变量,出了try结构就不能调用;
  7.try catch finally 结构可以嵌套

例如:

@Test
    public void test2() {
        int a= 10;
        int b = 0;
        try {
            System.out.println(a / b); 
        } catch(ArithmeticException e){
            e.printStackTrace();
        }finally {
            System.out.println("finally~~~");
            // : handle finally clause
        }
    }

该程序 Junit通过,控制台打印异常和finally~~~;因为程序执行到 System.out.println(a / b); b=0所以 出现了错误,生成ArithmeticException对象,与catch中的异常进行匹配,匹配上后,进行异常处理,处理完成,执行finally中的代码;

 1     @Test
 2     public void test3() {
 3 
 4         Day16ErrorAndExceptionDiscriable6 tt = new Day16ErrorAndExceptionDiscriable6();
 5         
 6         System.out.println(tt.finallyTest());
 7     }
 8 
 9 public int finallyTest() {
10     try {
11         int[] arr = new int[10];
12         //System.out.println(arr[10]); 打开或者关闭,return都是3; 3之前是inally~~~
13         return 0;
14     } catch(ArrayIndexOutOfBoundsException e){
15         e.printStackTrace();
16         return 1;
17     }finally {
18         System.out.println("finally~~~");
19         return 3;
20         // : handle finally clause
21     }
22 }

必须要处理的异常:如若需要调用时,必须要处理异常,或者是再往上抛出异常;

 1 public void method() throws FileNotFoundException,IOException{
 2     File file = new File("hello.txt");
 3     FileInputStream fis = null;
 4     fis = new FileInputStream(file);
 5     int data = fis.read();
 6     while(data != -1) {
 7         data = fis.read();
 8     }
 9     fis.close();
10 }
11 
12 public void method2() throws FileNotFoundException,IOException{
13             method();
14 }
 1 @Test
 2     public void test4() {
 3         File file = new File("hello.txt");
 4         FileInputStream fis = null;
 5         try {
 6             fis = new FileInputStream(file);
 7             int data = fis.read();
 8             while(data != -1) {
 9                 data = fis.read();
10             }
11         } catch (FileNotFoundException e) {
12             e.printStackTrace();
13         }catch (IOException e) {
14             e.printStackTrace();
15         }finally {
16             try {
17                 if(fis != null) {
18                     fis.close();
19                 }
20             } catch (IOException e) {
21                 // TODO Auto-generated catch block
22                 e.printStackTrace();
23             }
24         }
25         
26         
27     }

体会:

  try catch finally真正把异常处理掉,
  throws 的方式只是将异常抛给了方法的调用者,并没有真正的处理掉异常

 开发中,如何选择try catch finally OR throws?
  1.如果父类中被重写的方法没有throws,则子类重写的方法也不能throws,意味着如果子类重写的方法有异常,必须用try catch finally;
 2.执行的方法A中,先后又调用了另外的几个方法,这几个方法是递进的关系执行的,建议这几个方法使用throws的翻翻,而执行的方法A可以考虑使用try catch finally;

 四、如何自定义异常
 1.继承于现有的异常体系RuntionExceptioin  Exception
  2.提供全局常量:serialVersionUID;表示类是否是同一个类

1 class MyException extends RuntimeException{
2     static final long serialVersionUID = 1111111111111111l;
3     public MyException() {
4         
5     }
6     public MyException(String message) {
7         super(message);
8     }
9 }
 1 class Student{
 2     private int id;
 3     public void regist(int id) {
 4         if(id>0) {
 5             this.id = id;
 6         }else {
 7             //throw new RuntimeException("您输入的数据非法");//可以不处理,如果是Exceprion ,必须处理;
 8             throw new MyException("您输入的数据非法");//抛出自定义异常
 9         }
10     }
11     public void regist1(int id) throws Exception {
12         if(id>0) {
13             this.id = id;
14         }else {
15             throw new Exception("您输入的数据非法");//可以不处理,如果是Exceprion ,则需要处理(两种方式),因为exception包括编译异常,所以必须要处理
16             
17         }
18     }
19 }