异常
▶ 异常概念
异常:指程序在执行过程中出现非正常的情况,最终会导致 jVM 的非正常停止
在 java 等面向对象的编程语言中,异常本身就是一个类,产生异常就是创建异常对象并抛出一个异常对象
java 处理异常的方式是中断处理
【 异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行 】
▶ 异常体系
异常机制其实是帮助我们找到程序中的问题
异常的根类是:java.lang.Throwable ,其下面有两个子类:java.lang.Error 和 java.lang.Exception
【 注:平常所说的异常是指 java.lang.Exception 】
Throwable 体系:
- Error :严重错误Error ,无法通过处理的错误,只能事先避免,就像绝症一样
- Exception:表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的,就像感冒一样
▶ 异常产生过程的解析
编辑
编辑
这里访问了数组中的3索引,而且数组是没有3索引的,所以JVM就会检测出程序出现异常,则此时JVM会做两件事情:
(1)JVM会根据异常产生的原因创建一个异常对象,这个异常对象包含了异常产生的内容、原因、位置
new ArrayIndexOutOfBoundsException( " 3 " ) ;
(2)在getElement方法中没有异常的处理逻辑(try...catch),JVM就会把异常对象抛出给方法的调用者main方法来处理这个异常
main方法接收到了这个异常对象,main方法也没有异常的处理逻辑继续把对象抛出给main方法的调用者JVM处理
JVM接收到了这个异常对象做了两件事情:
① 把异常对象(内容、原因、位置)以红色的字体打印在控制台
② JVM会终止当前正在执行的 java 程序 ---> 中断处理
▶ 异常的处理
java异常处理的五个关键字:try、catch、finally、throw、throws
--- throw关键字
作用:可以使用throw关键字在指定方法中抛出指定的异常
使用格式:throw new xxxException( " 异常产生的原因 ") ;
注意:
1. throw关键字必须写在方法的内部
2. throw关键字后边的new的对象必须是Exception或者Exception的子类对象
3. throw关键字抛出指定的异常对象,我们就必须处理这个异常对象
throw关键字后边创建的是RuntimeException或者是RuntimeException的子类对象,可以不处理,默认交给JVM处理(打印异常对象,中断程序)
throw关键字后边创建的是编译异常(写代码的时候报错)则必须处理这个异常,要么throws,要么try...catch
--- throws关键字
异常处理的第一种方式,交给别人处理
作用:当方法内部抛出异常对象的时候,我们就必须处理这个异常对象,可以使用throws这个关键字处理异常对象, 会把异常对象声明抛出给方法的调用者处理(自己不处理,给别人处理)最终交给JVM处理 ---> 中断处理
使用格式:在方法声明时使用
修饰符 返回值类型 方法名(参数列表) throws AAAException,BBBException...{
throw new AAAException(“ 产生原因 ”) ;
throw new BBBException(“ 产生原因 ”) ;
}
注意:1. throws关键字必须写在方法声明处
2. throws关键字后边声明的异常必须是Exception或者是Exception的子类
3. 方法内部如果抛出多个异常对象,那么throws后边也必须声明多个异常
如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可
4. 调用了一个声明抛出异常的方法,就必须处理声明的异常
要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM
要么try...catch自己处理异常
编辑
--- try...catch关键字
try...catch异常处理的第二种方式,自己处理异常
格式:
编辑
注意: 1. try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些异常对象
2. 如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try...catch之后的代码 ;如果try中没有产生异常,那么就不会执行catch中异常的处理逻辑,执行完try中的代码就继续执行try...catch之后的代码
编辑
输出:
编辑
--- finally代码块
finally作用:有一些特定的代码无论异常是否发生都需要执行,因为异常会引发程序跳转,从而导致有些语句执行不到,而 finally 就是解决这个问题的,在 finally 代码块中存放的代码都是一定会被执行的。
什么时候的代码必须最终执行:当在 try 语句块中打开了一些物理资源(磁盘文件/网络连接/数据库连接等),都得在使用完之后最终关闭打开的资源
格式:
编辑
注意: 1. finally 不能单独使用,必须和try一起使用
2. finally 一般用于资源释放(资源回收),无论程序是否出现异常,最后都要资源释放(IO)
编辑
▶ Objects 非空判断
Objects类由一些静态的实用方法组成,这些方法是null-save(空指针安全的)或null-tolerant(容忍空指针的),在它的源码中,对对象为null的值进行了抛出异常的操作。
--- public static <T> T requireNonNull( T obj ) :查看指定引用对象不是null
源码:
编辑
从源码中可以发现这里对为null的对象进行了抛出异常的操作
▶ Throwable 类中3个异常处理的方法
(1)String getMessage() :返回此 throwable 的简短描述
(2)String toString() :返回此 throwable 的详细消息字符串
(3)void printStackTrace() :JVM打印异常对象,默认此方法打印的异常信息是最全面的
编辑
▶ 异常的注意事项
● 多个异常使用捕获该如何处理呢 ?
1. 多个异常分别处理
编辑
2. 多个异常一次捕获,多次处理
编辑
3. 多个异常一次捕获,一次处理
编辑
【 运行时异常被抛出可以不处理,即不捕获也不声明抛出 ,默认给虚拟机处理,终止程序,什么时候不抛出运行时异常了,再来继续执行程序 】
● 如果finally 有return 语句,永远返回 finally 中的结果,避免该情况
编辑
● 子父类异常
如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常
如果父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常,此时子类产生该异常,只能捕获处理,不能声明抛出
注意: 父类异常时什么样,子类异常就什么样
编辑
▶ 自定义异常类
java提供的异常类不够我们使用,需要自定义一些异常类
格式:
public class XXXException extends Exception / RuntimeException {
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
注意: 1. 自定义异常类一般都是以 Exception 结尾,说明该类是一个异常类
2. 自定义异常类,必须的继承 Exception 或者 RuntimeException
继承Exception :那么自定义的异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try...catch
继承RuntimeException :那么自定义的异常就是一个运行期异常,无需处理,交给虚拟机处理(中断处理)
编辑
自定义异常类练习:
--- 要求:模拟注册操作,如果用户名已存在,则抛出异常并提示 :亲,该用户名已被注册
--- 分析:
1.使用数组保存已经注册过的用户名(数据库)
2.使用Scanner获取用户输入的注册的用户名(前端,页面)
3.定义一个方法,对用户输入的已注册用户名进行判断
遍历存储已经注册过用户名的数组,获取每一个用户名
使用获取到的用户名和用户输入的用户名比较
true:
用户名已经存在,抛出RegisterException异常,告知用户“亲,该用户名已经被注册”
false:
继续遍历比较
如果循环结束了,还没有找到重复的用户名,提示用户:“恭喜您,注册成功!”
编辑