异常处理机制

Posted xfbb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异常处理机制相关的知识,希望对你有一定的参考价值。

1.异常处理

1.1 概念:

异常就是程序在运行中出现不正常的情况并终止了程序的运行。

JAVA中通过异常处理机制解决异常问题,从而保持程序继续运行;因此JAVA是一门比较稳定的语言。

技术图片

异常处理机制的关键字:try...catch...finally/try...catch

1.2 try...catch

解释:将有可能出现异常的语句放到try中,当出现异常时catch会捕获到

技术图片

【1】printStackTrace:打印异常执行的堆栈信息

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)

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

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

最后一行:异常出现的位置(类->方法->方法具体的行)

在控制台中异常堆栈信息输出位置不固定

 

【2】getMessage:返回异常的描述信息

 1 package cn.sxt02.exception02;
 2 import java.util.Scanner;
 3 public class Test01 {
 4     public static void main(String[] args) {
 5         Scanner sc = new Scanner(System.in);
 6         System.out.println("请输入第一个数:");
 7 
 8         int num1 = 0;
 9         int num2 = 0;
10         
11         try {
12             num1 = sc.nextInt();
13 
14             System.out.println("请输入第二个数:");
15             num2 = sc.nextInt();
16 
17             int r = 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     }
34 }

 

【3】异常类型不匹配

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

Exception是所有异常直接或间接的父类,因此当出现异常类型不匹配的时候可以这样写catch (Exception e)或者

catch省略,变成try…finally块;

1.3 try...catch...finally

finally块用于进行收尾工作(关闭数据库、关闭文件、释放内存等资源)

无论出不出现异常finally模块都会执行,当然也有特殊情况那就是添加一句system.exit();正常退出jvm,finally就不会执行

 1 public static void main(String[] args) {
 2         Scanner sc = new Scanner(System.in);
 3         System.out.println("请输入第一个数:");
 4 
 5         int num1 = 0;
 6         int num2 = 0;
 7 
 8         try {
 9             num1 = sc.nextInt();
10 
11             System.out.println("请输入第二个数:");
12             num2 = sc.nextInt();
13 
14             int r = 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.4 return

return 会出现try/catch/finally执行顺序

 1 package cn.sxt02.exception03;
 2 
 3 /**
 4  * 存在return的情况
 5  */
 6 public class Test02 {
 7 
 8     public static int div(int a, int b) {
 9 
10         try {
11             int r = a / b;
12             return r;
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     public static void main(String[] args) {
26 
27         int r = Test02.div(10, 0);
28         System.out.println("r=" + r);
29         System.out.println("程序正常结束");
30     }
31 }

解释:先执行try模块然后执行cacth,在执行finally 最后才执行return 0;以上例子为例

2.异常分类

技术图片

从上图可知异常和错误的最终父类都是object,异常分为两类运行时异常(RuntimeException)和检查时异常(CheckException)

2.1 RuntimeExcption

运行时异常可处理可不处理

2.2 CheckException

检查时运行必须得处理,不然将无法编译

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

2.3 常见的运行时异常(面试题写出5-8个)

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

InputMismatchException:输入不匹配异常

ArrayIndexOutofBoundsException:数组下标越界异常。

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

IllegalArgumentException:非法参数异常。

ClassCastException:强制类型转换异常。

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

2.4 常见的检查时异常:

ClassNotFoundException:类没有被发现异常。

SQLException:数据库相关异常

IOException:IO操作异常

ParseException:解析错误异常

FileNotFoundException:文件未发现异常。

2.5 运行时异常和检查时异常的区别

运行时异常:包括RuntimeException及其所有子类。不要求程序必须对它们作出处理,比如InputMismatchException、ArithmeticException、NullPointerException等。即使没有使用try-catch或throws进行处理,仍旧可以进行编译和运行。如果运行时发生异常,会输出异常的堆栈信息并中止程序执行。

Checked异常(非运行时异常):除了运行时异常外的其他异常类都是Checked异常。程序必须捕获或者声明抛出这种异常,否则出现编译错误,无法通过编译。处理方式包括两种:通过try-catch捕获异常,通过throws声明抛出异常从而交给上一级调用方法

 

3.异常声明

3.1 throws关键字

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

 

 1 public class Test01 {
 2 
 3     public static int div(int a, int b) throws ArithmeticException{
 4         int r = 0;
 5         r = a / b;
 6         return r;
 7     }
 8 
 9     public static void main(String[] args) {
10         try {
11             Test01.div(10, 0);
12         } catch (ArithmeticException e) {
13             System.out.println("除数不能为0");
14         }
15     }
16 }

 

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

如果调用处也不知道如何处理异常,可选择继续声明异常,我们把这个过程称为异常上抛。

 1 public class Test01 {
 2 
 3     public static int div(int a, int b) throws Exception{
 4         int r = 0;
 5         r = a / b;
 6         return r;
 7     }
 8 
 9     public static void 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 }

3.2 声明异常与重载关系

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

 

 1 public class Test01 {
 2 
 3     public static int div(int a, int b) throws Exception{
 4         int r = 0;
 5         r = a / b;
 6         return r;
 7     }
 8     
 9     public static int div(int a, int b) {
10         int r = 0;
11         r = a / b;
12         return r;
13     }
14 }

 

方法重载

【1】方法名相同
【2】参数列表不同(个数、类型、顺序)

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

3.3 声明异常和重写关系

 

【1】声明一个和方法重写有关系

 

 1 public class Father {
 2 
 3     public void showInfo() throws Exception{
 4         
 5     }
 6 }
 7 
 8 public class Son extends Father{
 9     
10     @Override
11     public void showInfo(){
12         
13     }
14     
15 }

 

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

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

 

 1 public class Father {
 2 
 3     public void showInfo(){
 4         
 5     }
 6 }
 7 public class Son extends Father{
 8     
 9     @Override
10     public void showInfo() throws Exception{
11         
12     }
13     
14 }

 

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

 

 1 public class Father {
 2 
 3     public void showInfo() throws Exception{
 4         
 5     }
 6 }
 7 public class Son extends Father{
 8     
 9     @Override
10     public void showInfo() throws Exception {
11         
12     }
13     
14 }

 

 

 

 

 

 

 

 

4.手动抛出异常

4.1  关键字throw

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

 1 package cn.sxt02.exception06;
 2 
 3 public class Student {
 4     private String name;
 5     private String gender;
 6 
 7     public String getName() {
 8         return name;
 9     }
10 
11     public void setName(String name) {
12         this.name = name;
13     }
14 
15     public String getGender() {
16         return gender;
17     }
18 
19     public void setGender(String gender) throws Exception{
20         if(gender.equals("男") || gender.equals("女")) {            
21             this.gender = gender;
22         }else {
23             throw new Exception("性别不合法!");
24         }
25     }
26 
27     public Student(String name, String gender) {
28         super();
29         this.name = name;
30         this.gender = gender;
31     }
32 
33     public Student() {
34         super();
35     }
36     
37 }
38 
39 public class Test01 {
40     public static void main(String[] args){
41         Student stu = new Student();
42         stu.setName("二狗");
43         try {
44             stu.setGender("xxx");
45         } catch (Exception e) {
46             System.out.println(e.getMessage());
47         }
48     }
49 }

4.2  自定义异常

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

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

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

 1 public class AgeException extends Exception{
 2 
 3     public AgeException() {
 4         super();
 5     }
 6 
 7     public AgeException(String message) {
 8         super(message);
 9     }
10     
11 }

 

以上是关于异常处理机制的主要内容,如果未能解决你的问题,请参考以下文章

PHP异常处理机制

异常及异常的处理机制

Java面向对象编程之异常处理机制

java异常处理机制

java异常处理的机制有哪几种

JAVA中的异常处理机制的原理