异常Exception
目录
【疑点】
带有finally的语句执行顺序
1.异常概述
异常是程序运行中的特殊情况
1.1 Throwable类
Throwable是Java中所有异常和错误的基类,位于java.lang包下
--| Error 错误:硬件异常,虚拟机异常,执行逻辑错误
--| Exception 异常:程序在执行期间或配置中发生错误,可处理
构造方法:
Throwable();
创建一个Throwable类对象,其中保存的异常或者错误信息为null
Throwable(String message); 【重点】
创建一个Throwable类对象,其中保存的异常或者错误信息为message
成员方法:
String toString();
得到当前异常的简要信息描述
String getMessage();
获取当前Throwable类对象中保存的异常或者错误信息
void printStackTrace(); 【伪重点】
在命令行中展示错误的前因后果!!!红色字体
1.2 Error和Exception
Error 错误
无法处理,只能避免!!!
错误都是Error结尾
Exception 异常
可以处理,还有挽回的余地
异常都是Exception结尾
【举例】
Java代码中有一个数组需要申请64GB内存,(目前电脑内存32GB)
不可能!!!错误 Error
Java中代码需要一个数组,但是给予的操作不合法
可以处理的,Exception
Exception
--| RuntimeException(非检测异常):运行期异常,可处理可不处理,可通过编译
--| CheckException(受查异常,检测异常):必须处理,不处理不能编译
1. 异常处理
1.1 Exception的两种处理方式概述
小门诊
手指划伤,需要包扎处理,当场处理好
发烧去小门诊,不敢接,要不您去指定发烧医院
当场处理好,拒之门外。
这两种方式就是Java中处理异常的方式
【捕获】 有能力处理你就捕获,自己的问题你就捕获
【抛出】 没有办法处理,或者不是自己的问题,和自己无关,因别人导致的错误,抛出
1.2 捕获异常
1.2.1 基本格式
格式:
try {
// 有可能出现问题的代码,存在一定隐患的代码
} catch (异常类型) {
// 对应当前异常类型的处理方式
// 【因为技术所限,我们只能sout 或者 printStackTrace 后期我们会使用日志log】
}
public class Demo1 {
public static void main(String[] args) {
int num1 = 0;
int num2 = 20;
int ret = 0;
/*
* num2 / num1 是存在一定的隐患的,如果num1保存的数据是0,
* 这里会出现一个算术异常
*/
try {
// 有可能出现异常的代码
ret = num2 / num1;
} catch (ArithmeticException e) {
/*
* ArithmeticException 算术异常,catch块中捕获对应异常
* catch大括号内是对应的处理方式,现在只能展示效果
*/
e.printStackTrace();
}
System.out.println(ret);
/*
* java.lang.ArithmeticException: / by zero
* at com.qfedu.a_exception.Demo1.main(Demo1.java:16)
* 0
*/
}
}
1.2.2 细节问题和注意事项
1. 代码中出现异常,JVM会终止代码运行,如果使用try catch捕获处理异常,JVM会认为当前代码中不存在异常,可以继续运行。
【类比】球员受伤,下场处理,处理完毕,回到场上
2. 在try大括号内或者catch大括号内都是局部变量,处理操作数据时小心谨慎。
3. try - catch捕获处理异常,可以处理多种异常情况!!!而且建议异常处理分门别类,对症下药
4. 代码中存在多种隐患,存在多个异常情况,try - catch捕获有且只能处理第一个出现异常的代码,因为JVM从异常代码开始直接进入异常捕获阶段
5. Exception作为Java中所有异常的超类,在捕获异常处理时如果直接使用Exception进行捕获处理,无法做到异常对症下药操作。
6. Exception可以作为try - catch 最后一个,用于处理其他异常捕获之后没有对症方式遗留问题。[不多见]
7. 多个异常时,无继承关系的异常没有上下排列要求,有继承关系的异常需要子类在上,父类在下
1.3 抛出异常
1.3.1 基本格式
关键字:
throw
在方法内特定条件下抛出指定异常
throws
在【方法声明】位置,【形式参数列表之后】,告知调用者,当前方法有哪些异常抛出
用于处理非当前方法操作问题,导致出现的异常,一般情况下是用于处理方法运行过程中因为参数传入,参数处理,运算结果导致的问题,抛出异常。
throw是一个高级的参数合法性判断!!!
/*
* throws 关键字在方法声明位置告知当前方法的调用者,这里存在异常信息
*/
/**
* 测试方法
*
* @param num1 int类型参数
* @param num2 int类型参数
* @throws ArithmeticException 如果除数为0,当前方法抛出算术异常
*/
public static void test(int num1, int num2)
throws ArithmeticException {
/*
参数合法性判断 之前的方式 low
if (0 == num2) {
System.out.println("你个瘪犊子...坑我");
System.exit(0);
}
*/
// 参数合法性判断,如果num2 为0, 这里存在隐患
if (0 == num2) {
/*
* 存在异常,这里创建一个异常对象抛出,这里构造方法中
* 存在无参数构造方法和有参数构造方法
* 无参数构造方法异常信息为null
* 有参数构造方法可以传入一个String类型数据,异常信息为指定字符串内容
*/
throw new ArithmeticException("除数不能为0");
}
// 如果num2的值为0,num1 / num2 操作是存在隐患的,有问题的
int ret = num1 / num2;
System.out.println(ret);
}
finally
无论上面是否有异常finally都会执行,通常用于:
1.释放资源
2.无论是否异常都需执行的代码
【执行地位优于try中的return】
1.3.2 细节问题和注意事项
1. 代码如果运行到throw抛出异常,之后的代码不再运行,之后的代码是成为无参触及代码
2. 代码中存在多种隐患,按照隐含的情况,分门别类处理,不能在同一个条件内抛出两个异常。并且在方法的声明位置,throws之后,不同的异常,使用逗号隔开
3. 当调用带有异常抛出的方法时,对于方法抛出的异常,有两种处理方式,可以捕获处理,也可以抛出处理。
1.4 抛出处理和捕获处理选择
情况分析:
用户查询指定路径指定名字的文件,存在的异常处理分析过程
1.5 异常分类
运行时异常:
RuntimeException 代码运行过程中出现的异常,没有强制处理的必要性
ArrayIndexOutOfBoundsException 数组下标越界异常
NullPointerException 空指针异常
ArithmeticException 算术异常
运行时异常不强制要求捕获和抛出!!!
JVM会处理RuntimeException,也就是告知异常的前因后果!!!
其他异常:
强制要求处理,不管是捕获处理,还是抛出处理,都需要进行操作。
如果未处理!!!直接报错!!!
IDE工具的快速修复
Eclipse Ctrl + 1
IDEA Alt + Enter
1.6 自定义异常
业务逻辑存在需求,但是Java中没有合适的异常来描述对应情况,自定义异常
自定义异常格式:
class MyException extends Exception {
// 无参数构造方法
public MyException() {}
// 有参数构造方法,且参数数据类型为String类型
public MyException(String message) {
super(message);
}
}
RuntimeException和Exception选择:
根据业务需求选择是否需要抛出
【注意】
Eclipse会提示要求完成一个ID号,可以忽略,存在一个警告,不用管。
package exception;
public class CustomException {
public static void main(String[] args) {
Student s = new Student();
try {
s.setAge(5060);
} catch (AgeException e) {
System.out.println("年龄必须在0~200之间");
System.out.println(e.toString());//得到异常的简要信息描述,来自于Throwable
System.out.println(e.getMessage());//得到异常的简要信息描述,来自于Throwable
e.printStackTrace();
}
System.out.println("程序结束");
}
}
/**
* 自定义异常: 定义有参无参构造方法,有参构造方法在【自行抛出异常位置】可以增加提示信息
* 在【捕获异常】处增加e.printStackTrace()可以说输出提示信息
* 自定义异常会要求完成一个异常,可以忽略,存在一个报警,不用管
* 定义学生年龄的受查异常
*/
class AgeException extends Exception {
// 定义无参构造方法
public AgeException() {
}
/**
* 异常的有参构造,需要的参数是String类型的参数
* @param message 异常的提示信息
*/
public AgeException(String message) {
/*
* 通过super关键字调用父类的构造方法
*/
super(message);
}
}
/*
* 定义学生性别运行时异常
*/
class SexException extends RuntimeException {
public SexException() {
}
public SexException(String message) {
super(message);
}
}
class Student {
private int age;
private String sex;
public void setAge(int age) throws AgeException {
if (age > 200) {
throw new AgeException("年龄输入非法");
}
this.age = age;
}
public void setSex(String sex) {
if (sex.equals("男") || sex.equals("女")) {
this.sex = sex;
} else {
throw new SexException("性别输入非法");
}
}
}
1.7 异常处理总结
1. 异常存在的必要性,代码中使用的数据,大多数来源于用户,用户传入数据是一个非常不可靠的情况!!!存在一定错误意识,反馈机制和处理机制。
2. 异常处理方式
捕获
抛出
要根据使用情况,操作方式,反馈形式来选择对应的处理方式。
3. 自定义异常,了解异常的构造,基本上在开发中用到自定义异常的情况不多见。但是要了解关于异常信息保存的方式。
1.8 接口,继承下的异常
方法名,返回值类型,参数列表和父类相同
子类访问修饰符比父类更大
子类(实现类)中的方法异常不能比父类(接口)更宽