异常的概述
不正常的情况
未预料到的情况
生活中的异常
例如:正常情况下,上班需要花费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:
请输入第1个操作数:b
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:11)
异常情况2:
请输入第1个操作数:10
请输入第2个操作数:0
Exception in thread "main" java.lang.ArithmeticException: / by zero
at demo03.Demo01.main(Demo01.java:16)
采用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("对不起!除数不能为零!");
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抓住相应异常,然后进行异常处理,会继续向下执行try-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) {
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.Demo02.main(Demo02.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.Demo01.main(Demo01.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 区别。
throw后面接对象
throws声明方法
Java中的异常体系结构
Throwable:可抛的
- Error : 错误,是必须通过修改代码或修改环境才能解决的问题
- Exception:顶级父类,异常还可以修复
- RuntimeException运行时异常,不要求立即处理,运行时可能出错,也可能不出差
-
InputMismatchException:输入不匹配异常
-
IllegalArgumentException:非法参数异常
-
NullPointerException:NPE,空指针异常
-
ClassCastException:类型转换异常
-
ArraysIndexOutofBoundsException:数组下标越界异常
-
- RuntimeException运行时异常,不要求立即处理,运行时可能出错,也可能不出差
- 受检异常,要求立即处理(因为Java认定这种错误很可能出现)
- FileNotFoundException 文件找不到异常
- SQLException
- ....
自定义异常
自定义异常 is a Exception类/RuntimeException
/*
* 自定义的异常
* */
public class IllegalHealthException extends RuntimeException {
public IllegalHealthException() {
super();
}
public IllegalHealthException(String message) {
super(message);
}
}