异常处理(try...catch...final 和 throw , throws)

1.传统(弱语言)处理异常方式

原理:利用判断来控制异常出现

 

 1 publicclass Test01 {
 2     publicstaticvoid main(String[] args) {
 3         Scanner sc = new Scanner(System.in);
 4         System.out.println("请输入第一个数:");
 5         
 6         intnum1 = 0;
 7         if(sc.hasNextInt()) {            
 8             num1 = sc.nextInt();
 9             
10             System.out.println("请输入第二个数:");
11             intnum2 = 0;
12             if(sc.hasNextInt()) {
13                 num2 = sc.nextInt();
14                 
15                 if(0 == num2) {
16                     System.out.println("除数不能为0!");
17                 }else {                    
18                     intr = num1 / num2;
19                     System.out.println("num1/num2 = "+r);
20                 }
21 
22             }else {
23                 System.out.println("第二个数输入不是数字");
24             }
25             
26         }else {
27             System.out.println("第一个数输入不是数字!");
28         }
29     }
30 }

 

这样做的缺点:

【1】通过判断处理异常影响执行效率。

【2】判断逻辑和业务逻辑交织在一起,不利于后期维护。

2.异常

异常是所有异常类的直接或间接父类。

异常是指在运行过程中发生了不正常的情况,这是它就会中断程序。

异常处理机制:指java中异常处理机制为程序提供处理异常的能力,从而使程序不中断的运行。

 

 3.异常处理

异常处理的关键字有:try...catch 和 try...catch...finally  

1)try...catch

解释:try— 把有可能产生异常的代码放到try代码块中,catch—负责捕获异常并匹配异常再处理异常。

【1】正常执行,没有遇到异常

【2】出现异常,异常处理,正常结束。(红字是处理异常步骤)

异常常见方法:

prinStackTrace:打印异常的执行堆栈信息(在控制台中异常堆栈信息输出位置不固定)

1 java.util.InputMismatchException
2     at java.util.Scanner.throwFor(Scanner.java:864)
3     at java.util.Scanner.next(Scanner.java:1485)
4     at java.util.Scanner.nextInt(Scanner.java:2117)
5     at java.util.Scanner.nextInt(Scanner.java:2076)
6     at cn.sxt02.exception02.Test01.main(Test01.java:14)

一般,异常的堆栈信息很多,开发者只需要看懂

 ——第一行:异常简单的信息(异常类型,异常描述等)

——最后一行:异常出现的位置(如上的Test01.java:14)

getMessage:返回异常的描述信息

 1 packagecn.sxt02.exception02;
 2 importjava.util.Scanner;
 3 publicclass Test01 {
 4     publicstaticvoid main(String[] args) {
 5         Scanner sc = new Scanner(System.in);
 6         System.out.println("请输入第一个数:");
 7 
 8         intnum1 = 0;
 9         intnum2 = 0;
10         
11         try {
12             num1 = sc.nextInt();
13 
14             System.out.println("请输入第二个数:");
15             num2 = sc.nextInt();
16 
17             intr = num1 / num2;
18             System.out.println("num1/num2 = " + r);
19         }catch (Exception e) {
20             System.out.println("程序出现异常");
21             // 打印异常的信息
22             // System.out.println(e.toString());
23             
24             
25             // 打印异常堆栈信息
26             e.printStackTrace();
27             
28             // 返回异常的描述信息,如果没有信息,返回null(InputMismatchException没有描述信息)
29             System.out.println(e.getMessage());
30         }
31         
32         System.out.println("程序正常结束");
33     }

【3】异常类型不匹配

【4】多重catch

 1 publicclass Test03 {
 2     publicstaticvoid main(String[] args) {
 3         Scanner sc = new Scanner(System.in);
 4         System.out.println("请输入第一个数:");
 5     
 6         intnum1 = 0;
 7         intnum2 = 0;
 8         
 9         try {
10             num1 = sc.nextInt();
11 
12             System.out.println("请输入第二个数:");
13             num2 = sc.nextInt();
14 
15             intr = num1 / num2;
16             System.out.println("num1/num2 = " + r);
17         }catch (ArithmeticExceptione) {
18             System.out.println("数学计算异常:"+e.getMessage());
19         }catch(InputMismatchExceptione) {
20             System.out.println("输入不匹配异常:"+e.getMessage());
21         }catch (Exception e) {
22             System.out.println("发送异常:"+e.getMessage());
23         }
24         
25         System.out.println("程序正常结束");
26     }
27 }

2)try...catch...finally  

 解读:把有可能产生异常的代码放到try的代码块中,catch捕捉异常并匹配异常再处理异常,finally块用于收尾工作

(如关闭数据库,关闭文件,释放内存等资源)

注:finally :无论是否发生异常,finally都将执行,常用于收尾工作

 1 publicstaticvoid main(String[] args) {
 2         Scanner sc = new Scanner(System.in);
 3         System.out.println("请输入第一个数:");
 4 
 5         intnum1 = 0;
 6         intnum2 = 0;
 7 
 8         try {
 9             num1 = sc.nextInt();
10 
11             System.out.println("请输入第二个数:");
12             num2 = sc.nextInt();
13 
14             intr = num1 / num2;
15             System.out.println("num1/num2 = " + r);
16         } catch (Exception e) {
17             System.out.println("程序出现异常");
18         } finally {
19             System.out.println("不管是否出现异常,finally都执行");
20         }
21 
22         System.out.println("程序正常结束");
23     }

特殊情况:

【1】finally不执行的情况

System.exit(0)正常退出jvm,程序结束,不会执行finally

【2】catch可以省略,变成try...finally形式

4.return

当return存在于try...catch...finally时的执行顺序(return始终在最后)

 

 1 packagecn.sxt02.exception03;
 2 
 3 /**
 4  * 存在return的情况
 5  */
 6 publicclass Test02 {
 7 
 8     publicstaticintdiv(inta, intb) {
 9 
10         try {
11             intr = a / b;
12             returnr;
13 
14         } catch (Exception e) {
15             System.out.println("出现异常");
16 
17             return 0;
18 
19         } finally {
20             System.out.println("我是finally");
21         }
22 
23     }
24 
25     publicstaticvoid main(String[] args) {
26 
27         intr = Test02.div(10, 0);
28         System.out.println("r=" + r);
29         System.out.println("程序正常结束");
30     }
31 }

 

5.异常的分类

Throwable类是 Java 语言中所有错误(Error)或异常(Exception)的父类,只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。

Error 类表示错误类。仅靠程序本身无法恢复的严重错误。如jvm内存耗尽、jvm崩溃等。

Exception类表示异常类,可以通过java 异常处理机制处理。

Exception根据是否处理分为两种情况。

RuntimeException:运行时异常。不要求程序必须做出处理。是所有运行时异常的父类。

CheckedException:检查时异常。要求程序必须处理,不处理编译不通过。

 1 publicclass Test01 {
 2     publicstaticvoid main(String[] args) {
 3         // 运行时异常
 4         Scanner sc = new Scanner(System.in);
 5         // runtime exception
 6         intr = sc.nextInt();
 7         System.out.println("r = "+ r);
 8         
 9         // 检查时异常
10         SimpleDateFormatdf = newSimpleDateFormat();
11         try {
12             Date date = df.parse("2019");
13         } catch (ParseExceptione) {
14             e.printStackTrace();
15         }
16     }
17 }

常见的运行时异常

ArithmeticException:数学计算异常。如除数为0

InputMismatchException:输入不匹配异常。

ArrayIndexOutofBoundsException:数组下标越界异常。

NullPointException:空指针异常,对象没有初始化就使用时,jvm就会抛出该异常。

IllegalArgumentException:非法参数异常。

ClassCastException:强制类型转化异常。

NumberFormatException:数字格式化异常。如把“abc”格式化为数字。

常见的检查时异常:

ClassNotFoundException:类没有被发现异常。

SQLException:数据库相关异常
IOException:IO操作异常
ParseException:解析错误异常
FileNotFoundException:文件未发现异常。
运行时异常和检查时异常的区别:

  运行时异常:包括RuntimeException及其所有子类。不要求程序必须对它们作出处理,比如InputMismatchException、                 ArithmeticException、NullPointerException等。即使没有使用try-catch或throws进行处理,仍旧可以进行

        编译和运行。如果运行时发生异常,会输出异常的堆栈信息并中止程序执行。

  检查时异常:Checked异常(非运行时异常):除了运行时异常外的其他异常类都是Checked异常。程序必须捕获或者

        声明抛出这种异常,否则出现编译错误,无法通过编译。处理方式包括两种:通过try-catch捕获异常,

        通过throws声明抛出异常从而交给上一级调用方法处理

6.声明异常

1)throws关键字

解读:当一个方法可能存在异常,而此时自身又无法更好的处理,可以交给外界处理。此时用throws声明并抛出异常。

 1 publicclass Test01 {
 2 
 3     publicstaticintdiv(inta, intb) throws ArithmeticException{
 4         intr = 0;
 5         r = a / b;
 6         returnr;
 7     }
 8 
 9     publicstaticvoid main(String[] args) {
10         try {
11             Test01.div(10, 0);
12         } catch (ArithmeticExceptione) {
13             System.out.println("除数不能为0");
14         }
15     }
16 }

  注:开发者可以根据需求声明检查时异常 (Exception或者非运行时异常及其子类)  和运行时异常(RuntimeException或其子类)

 如果抛出异常后,调用处不知道如何处理异常,可以选择继续声明异常(抛出异常),这个过程叫做异常上抛。

 1 publicclass Test01 {
 2 
 3     publicstaticintdiv(inta, intb) throws Exception{
 4         intr = 0;
 5         r = a / b;
 6         returnr;
 7     }
 8 
 9     publicstaticvoid main(String[] args) throws Exception{
10         
11         //【1】调用处知道如何处理!
12         /*
13         try {
14             Test01.div(10, 0);
15         } catch (Exception e) {
16             e.printStackTrace();
17         }
18         */
19         
20         // 【2】调用处也不知道如何处理
21         Test01.div(10, 0);
22         
23     }
24 }

2)声明异常和重载的关系

声明异常和重载没有任何关系

 1 publicclass Test01 {
 2 
 3     publicstaticintdiv(inta, intb) throws Exception{
 4         intr = 0;
 5         r = a / b;
 6         returnr;
 7     }
 8     
 9     publicstaticintdiv(inta, intb) {
10         intr = 0;
11         r = a / b;
12         returnr;
13     }
14 }

注:方法重载:

【1】方法名相同

【2】参数列表不同(个数,类型,不同类型的顺序不同)

【3】和返回值,修饰符,声明异常无关

 3)声明异常和重写的关系

声明异常和方法重写有关系,关系如下

[1]父类方法声明了异常(检测时或运行时),子类可以不声明任何异常。

publicclass Father {

    publicvoidshowInfo() throws Exception{
        
    }
}
publicclass Son extendsFather{
    
    @Override
    publicvoidshowInfo(){
        
    }
    
}

理解:父类方法抛出异常,子类在重写过程中把该异常处理掉了,所以子类方法不用声明异常。

[2] 父类方法声明没有声明任何异常(检测时或运行时),子类也不声明异常或者声明运行时异常。

publicclass Father {

    publicvoidshowInfo(){
        
    }
}
publicclass Son extendsFather{
    
    @Override
    publicvoidshowInfo() throws Exception{
        
    }
    
}

[3]父类声明了异常(检测时或运行时),子类声明完全一样的异常。

publicclass Father {

    publicvoidshowInfo() throwsException{
        
    }
}
publicclass Son extendsFather{
    
    @Override
    publicvoidshowInfo() throwsException {
        
    }
    
}

7.手动抛出异常

1)throw

除了系统自动抛出异常外,有些问题需要开发者手动抛出异常。使用关键字throw

 1 packagecn.sxt02.exception06;
 2 
 3 publicclass Student {
 4     private String name;
 5     private String gender;
 6 
 7     public String getName() {
 8         returnname;
 9     }
10 
11     publicvoidsetName(String name) {
12         this.name = name;
13     }
14 
15     public String getGender() {
16         returngender;
17     }
18 
19     publicvoidsetGender(String gender) throws Exception{
20         if(gender.equals("男") || gender.equals("女")) {            
21             this.gender = gender;
22         }else {
23             thrownew Exception("性别不合法!");
24         }
25     }
26 
27     publicStudent(String name, String gender) {
28         super();
29         this.name = name;
30         this.gender = gender;
31     }
32 
33     publicStudent() {
34         super();
35     }
36     
37 }
 1 publicclass Test01 {
 2     publicstaticvoid main(String[] args){
 3         Student stu = newStudent();
 4         stu.setName("二狗");
 5         try {
 6             stu.setGender("xxx");
 7         } catch (Exception e) {
 8             System.out.println(e.getMessage());
 9         }
10     }
11 }

2)自定义异常

理解:如果开发者需要手动抛出的异常在系统不存在,可以自定义异常。

注意:如果要自定义异常,首先要确定异常类型,如果异常是运行时异常,必须继承RuntimeException或其子类;如果异常是检查时异常,必须继承Exception或其子类。

     ——异常的命名方式,参考系统命名方式,以Exception结尾。

publicclassAgeExceptionextendsException{

    publicAgeException() {
        super();
    }

    publicAgeException(String message) {
        super(message);
    }
    
}

 

posted @ 2019-04-26 21:22  他也就火三年  阅读(1875)  评论(0编辑  收藏  举报