异 常

异常的概述

不正常的情况

意料之外的情况

生活中的异常

例如:正常上班情况下,需要35分钟。(开车/地铁)

出现车祸或者地铁停运,增加上班时间,这就是异常情况

异常情况会导致上班的程序中断。

计算机中的异常

需求:输入两个数值,进行除法运算。

Scanner input = new Scanner(System.in);
        
System.out.print("请输入第1个操作数:");
int num1 = input.nextInt();
System.out.print("请输入第2个操作数:");
int num2 = input.nextInt();
​
// 计算结果
int result = num1 / num2;
System.out.printf("%d / %d = %d\n", num1, num2, result);

正常情况:

请输入第1个操作数:10
请输入第2个操作数:2
10 / 2 = 5

异常情况1(除数为 0 ):

请输入第1个操作数:10
请输入第2个操作数:0
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at demo03.Demo01.main(Demo01.java:17)

异常情况2(输入 字符 ’a‘):

请输入第1个操作数:a
Exception in thread "main" java.util.InputMismatchException
    at java.util.Scanner.throwFor(Scanner.java:864)
    at java.util.Scanner.next(Scanner.java:1485)
    at java.util.Scanner.nextDouble(Scanner.java:2413)
    //  出现异常的直接地址
    at  demo03.Demo01.main(Demo01.java:12)

根据以上情况,使用 if 判断语句进行异常处理:

Scanner input = new Scanner(System.in);
​
System.out.print("请输入第1个操作数:");
if (!input.hasNextInt()) {
    System.out.println("对不起!请输入整数!");
    return;
}
int num1 = input.nextInt();
System.out.print("请输入第2个操作数:");
if (!input.hasNextInt()) {
    System.out.println("对不起!请输入整数!");
    return;
}
int num2 = input.nextInt();
if (num2 == 0) {
    System.out.println("对不起!除数不能为0!");
    return;
}
// 计算结果
int result = num1 / num2;
System.out.printf("%d / %d = %d\n", num1, num2, result);
​
对以上代码段的分析
  • 核心业务甚至不如错误判断代码多

  • 由于添加了大量的判断,导致代码阅读性大大降低

  • 即使添加了大量的 if 判断,也仅仅是一个查缺补漏的环节,并不能够保证所以异常都能被处理

Java异常处理机制

Java 提供了一套专业的异常处理机制。

5个关键词以及一套成熟的异常类的体系结构(以 Exception 类为顶级父类)。

  • try:尝试

  • catch:抓住

  • finally:最终地

  • throw:扔、抛

  • throws:扔、抛

try-catch(※)

基础try-catch

try{
    // 可能会出现异常的代码段
    // 尝试抓住异常的代码段
}catch(异常类型 变量名){
    //抓住异常后,如何处理异常
}
// 后续的代码段

在执行try块中的代码段,若没有出现异常,执行完try 块后继续向下执行 try-catch 后的内容

若在 try 块中出现异常,try 块中的代码段不再执行,直接由 catch 抓住相应异常,然后进行异常处理。但是,若 catch 声明的异常类型和实际出现的异常不匹配,那么异常采用默认形式处理。处理完异常后,继续向下执行try-catch 后的内容

优化后的需求

Scanner input = new Scanner(System.in);
​
try {
    System.out.print("请输入第1个操作数:");
    int num1 = input.nextInt();
    System.out.print("请输入第2个操作数:");
    int num2 = input.nextInt();
​
    // 计算结果
    int result = num1 / num2;
    System.out.printf("%d / %d = %d\n", num1, num2, result);
} catch (InputMismatchException e) { // InputMismatchException  为出现字符的异常情况
    System.out.println("对不起!请输入整数!");
}

多重catch

try {
    // 可能会出现异常的代码段
    // 尝试抓住异常的代码段
} catch(异常类型1 变量名) {
     //抓住异常后,如何处理异常
} catch(异常类型2 变量名) {
     //抓住异常后,如何处理异常
}

catch 可以写多个,指定不同的异常类型,这样就可以处理不同类型的异常了。

它的判断机制和多重 if 类似,也是自上而下判断异常类型,只要有一个异常类型匹配后续的就不再进行判断和处理了。

一般在多重 catch 最后还会添加一个 Exception 类型的捕获,因为多态(一切使用父类引用的地方,都可以传入其子类对象),所以所有的异常类型都可以匹配到 Exception 类型。

由于 Exception 类型是异常类型的顶级父类,所以一般没有特殊需求处理多种异常情况,可能在 catch 中只会声明捕获 Exception 这一个。

try {
​
} catch(Exception e) {
​
}

常见的异常处理

  1. 直接输出异常提示(System.out.println())

  2. 使用异常输出(System.err.println(),红色输出)

  3. 打印异常堆栈跟踪/信息(默认 JVM 就是这么处理的)

    • printStackTrace() : void

    • getMessage() : String 有些异常抛出时没有提示信息

    • 你自己打印和 JVM 默认打印的区别在于,JVM 默认打印完会中断程序

    // 异常发生在 main/主 线程 
    // 异常类型:异常提示信息
    // 异常出现具体位置:类、方法、行号
    Exception in thread "main" java.lang.ArithmeticException: / by zero
        at demo04.Demo01.main(Demo01.java:19)
    // 异常出现的具体位置提示,越向上,越是根本原因,越向下,越是直接原因。
    java.util.InputMismatchException
        at java.util.Scanner.throwFor(Scanner.java:864)
        at java.util.Scanner.next(Scanner.java:1485)
        at java.util.Scanner.nextInt(Scanner.java:2117)
        at java.util.Scanner.nextInt(Scanner.java:2076)
        at demo04.Demo04.main(Demo04.java:14)
  4. 自定义异常处理,根据需求决定

try-catch-finally

finally:无论是否出现异常,都会执行 finally 中的内容。

finally 中一般编写释放资源类的代码。

try {
    // 可能出现异常的代码段
} catch (异常类型 变量名) {
    // 异常处理
} finally {
    // 无论是否出现异常,都希望能执行
}

finally 和 return 在 try-catch 代码块中同时出现,它会先执行 finally 再执行 return。

try-finally(了解)

只想释放资源,而不想进行异常处理。

try {
    
} finally {
    
}

finally,catch 都需要配合 try 使用。

throw

在使用 JDK 提供的这些类时,如果出现了异常,实际上是 JDK 的这些类的代码中抛出了异常。

而如果我们以后写了一些程序,也出现了不合理的情况,我们也可以手动抛出异常,告诉调用者有什么问题。


try-catch是积极的处理方法,它主张发现异常,并处理异常。

throw 抛异常是一种消极的处理方法,它主张发现异常,抛上去让调用者解决。

但有些时候,却是是需要向上抛出,来让调用者知道你这有什么问题,才能进行合理的处理。


抛出异常对象的,一般配合 if 使用,在发现不合理的情况时,创建并抛出异常。

throw 异常对象;

throws

声明异常,声明该方法可能出现哪些异常。和 throw 一样都是一种相对消极的异常处理方法,让调用者来处理。

大多数用来标注方法中出现的受检异常。运行时异常一般通过 throw 直接把异常对象抛上去了。

访问权限修饰符 返回值类型 方法名(形式参数列表) throws 异常类型, ... {
    
}

throw 后面接着异常对象,在代码段中

throws 后面接着 异常类型 (可以接多个) 在方法声明中

Java 中的异常体系结构

Throwable:可抛的

  • Error:错误,是必须通过修改代码或修改环境才能解决的问题

  • Exception:顶级父类,异常可以修复

    • RuntimeException 运行时异常 ,不要求立即处理,运行时可能出错,也可能不出错

      • InputMismatchException:输入不匹配异常

      • IllegalArgumentException:非法参数异常

      • NullPointerException:NPE,空指针异常

      • ClassCastException:类型转换异常

      • ArrayIndexOutofBoundsException:数组下标越界异常

    • 受检异常,要求立即处理(因为 Java 认定这种错误很可能出现)

      • FileNotFoundException 文件找不到异常

      • SQLException

      • ...

自定义异常

自定义异常 is a Exception类/RuntimeException类

/*
 * 对健康值非法进行自定义的异常
 */
public class IllegalHealthException extends RuntimeException {
​
    public IllegalHealthException() {
        super();
    }
​
    public IllegalHealthException(String message) {
        super(message);
    }
    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值