目录
【疑点】
带有finally的语句执行顺序
1.异常概述
程序运行的过程中的非正常状况,与错误(Error)不同,Error是程序无法处理的状况,异常是可以通过程序来解决的状况,Exception与Error都是Throwable的直接子类
任何程序都有可能出现大量的问题或者异常,如果不对程序进行异常的处理,程序会在出现异常的代码处中断执行,导致程序无法继续。
异常存在的意义:让我们的程序在出现异常的代码之后还能够继续执行,而不至于直接中断后面代码的执行
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:Exception是所有异常的根
--| RuntimeException(非检测异常):运行期异常,可处理可不处理,可通过编译
--| CheckException(受查异常,检测异常):必须处理,不处理不能编译
检测异常:编译期间就要求处理的异常,后者try~catch,要么throws声明异常;
File f = new File();
f.creatNewFile();//此处会报警
1.3 异常五个关键字
try:尝试执行一段有可能发生异常的代码
catch:捕获,发生异常后要处理的代码块
finally:最终,不管是否发生异常,该代码块都将被执行
throws:异常的声明,在方法的头部要声明该方法中可能出现的所有异常对象
throw:在方法中出现异常是将异常交给下一个主调方法来处理
1. 异常处理
1.1 Exception的两种处理方式概述
小门诊
手指划伤,需要包扎处理,当场处理好
发烧去小门诊,不敢接,要不您去指定发烧医院
当场处理好,拒之门外。
这两种方式就是Java中处理异常的方式
【捕获】 有能力处理你就捕获,自己的问题你就捕获
【抛出】 没有办法处理,或者不是自己的问题,和自己无关,因别人导致的错误,抛出
捕获 try~~catch
抛出 throw在语句块处,throws在声明处
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. 捕获多个异常时,无继承关系的异常没有上下排列要求,有继承关系时需要子类异常在上,父类异常在下
8.两个相同的catch捕获时,下面的那个会成为unreachable code
9.异常的类型(try部分)和(catch部分)不匹配时,catch部分不会捕获不匹配的异常(try部分)
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);
}
1.3.2finally
无论上面是否有异常finally都会执行,通常用于:
1.释放资源
2.无论是否异常都需执行的代码
finally 和return的执行顺序。return可以加载try和finall的模块中,不能加在finally中,加在finally中会警告
finally执行顺序
package exception;
public class TryCatchFinally04 {
public static void main(String[] args) {
System.out.println(getNum());
}
/**
* try catch中return的变量,即使该变量在finally代码块中做了修改,
* 但是return的瞬间点的值是多少,我们该方法最终的返回值还是当时瞬间点的值。
*
* @return
*/
public static int getNum() {
int a = 0;
try {
return a;
} catch (Exception e) {
e.printStackTrace();
return -a;
}finally {
a++;
//return ++a;
}
//return 0;
}
}
0
package exception;
public class TryCatchFinally03 {
public static void main(String[] args) {
System.out.println(getNum());
}
/**
* finally的代码块会在try或者catch的return之前执行
* 假如finally中存在return,则整个方法的返回值就是finally的代码的return值
* @return
*/
public static int getNum() {
try {
System.out.println("try");
System.out.println(1 / 0);
//return 1;
} catch (Exception e) {
System.out.println("catch");
e.printStackTrace();
//return -1;
}finally {
System.out.println("finally");
}
return 0;
}
}
1.3.3 细节问题和注意事项
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(60);
} catch (AgeException e) {
System.out.println("年龄必须在0~200之间");
System.out.println(e.toString());//得到异常的简要信息描述,来自于Throwable
System.out.println(e.getMessage());//得到异常的简要信息描述,来自于Throwable
e.printStackTrace();
}
s.setSex("afds");
System.out.println("程序结束");
}
}
/**
* 自定义异常: 定义有参无参构造方法,有参构造方法在【自行抛出异常位置】可以增加提示信息
* 在【捕获异常】处增加e.printStackTrace()可以说输出提示信息
* 自定义异常会要求完成一个异常,可以忽略,存在一个报警,不用管
* 定义学生年龄的受查异常
*/
class AgeException extends Exception {
// 定义无参构造方法
public AgeException() {
}
/**
* 异常的有参构造,需要的参数是String类型的参数
* @param message 异常的提示信息
*/
public AgeException(String message) {
/*
* 通过super关键字调用父类的构造方法
*/
super(message);
}
}
/*
* 定义学生性别运行时异常
*
* SexException继承的是运行异常,在代码块中只抛出异常不在声明处进行声明不会报警
* 如果继承的是受查异常,只抛出不声明不会存在异常
*/
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("女"))) {
throw new SexException("性别输入非法");
} else {
this.sex = sex;
}
}
}
1.7 异常处理总结
1. 异常存在的必要性,代码中使用的数据,大多数来源于用户,用户传入数据是一个非常不可靠的情况!!!存在一定错误意识,反馈机制和处理机制。
2. 异常处理方式
捕获
抛出
要根据使用情况,操作方式,反馈形式来选择对应的处理方式。
3. 自定义异常,了解异常的构造,基本上在开发中用到自定义异常的情况不多见。但是要了解关于异常信息保存的方式。
1.8 接口,继承下的异常
方法名,返回值类型,参数列表和父类相同
子类访问修饰符比父类更大
子类(实现类)中的方法异常不能比父类(接口)更宽
【请简述你对异常的理解】
异常是程序运行时的意外情况。
异常位于java.lang包下,继承自Throwable类,为所有异常的基类。
程序运行时不发生异常情况时不可能的,程序发生异常时会停止运行,不能完成对应的服务。对于程序中的异常,我们可以通过一些对应的处理措施可以预防这种情况,在程序发生异常时还能继续运行下去,完成应有的功能。
异常可分为运行时异常和受查异常,受查异常在程序进行编写时就有错误提示,我们可以马上发现并进行修正。运行时异常需要我们了解程序运行情况,对可能出现问题的程序进行捕获或者声明。
程序在用户界面可能发生异常时要进行捕获处理,不能将异常展现给用户;在非用户界面,我们根据实际情况对异常进行捕获,抛出或者修正异常。