-
程序在执行过程中出现了非正常的情况,最终会导致虚拟机的非正常停止
-
Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出
Java处理异常的方式就是中断处理 -
异常 (Exception) JAVA健壮型的体现
-
补充:java特性:
- 简单,
- 面向对象,
- 多线程,
- 可移植,
- 跨平台,
- 解释执行,
- 健壮
一、异常和错误
java.lang.Throwable
类是Java语言中所有错误和异常的超类
- 错误Error: 致命性,导致堆栈溢出,程序无法运行,必须修改源代码
- 异常Exception: 不致命性,程序处理后,程序可以继续执行
- 编译时异常,进行编译(写代码)java程序出现的问题
- 运行时异常(RuntimeException
):java程序运行过程中出现的问题
常见的异常
- 算术异常类:
ArithmeticExecption
- 空指针异常类:
NullPointerException
- 类型强制转换异常:
ClassCastException
- 数组负下标异常:
NegativeArrayException
- 数组下标越界异常:
ArrayIndexOutOfBoundsException
- 字符串转换为数字异常:
NumberFormatException
- 方法未找到异常:
NoSuchMethodException
- 文件未找到异常:
FileNotFoundException
- 输入输出异常:
IOException
二、异常的处理
1.JVM默认处理异常的方式
-
JVM会根据异常产生的原因创建一个异常对象,
这个对象包含了异常产生的(内容、原因、位置) -
查找在被调用方法中是否含有异常的处理逻辑(try…catch),
如果没有JVM就会把异常对象抛给方法的调用者main()方法来处理这个异常 -
main方法接收这个异常对象,也没有异常处理逻辑,
继续把对象抛出给main()方法的调用者JVM处理 -
JVM接收到main()方法抛出的异常对象
- 把异常对象(内容、原因、位置)以红色字体打印在控制台中
- JVM会终止当前正在执行的java程序(中断处理)
2.抛出异常throw
throw关键字在指定方法中抛出指定异常
-
1.格式 throw new XxxException(“异常的原因”)
-
2.注意事项
- 必须写在方法内部
- 在后面的new的对象必须是Exception或者其子类对象
- 抛出指定的异常对象,调用者必须处理这个异常
- 抛出的时RuntimeException或者其子类对象,我们可以不处理
默认交给JVM处理(打印异常对象、中断程序) - 创建的是编译异常,我们就必须处理这个异常:
- throws声明抛出
- try…catch
- 抛出的时RuntimeException或者其子类对象,我们可以不处理
3.声明异常throws
异常处理的第一种方式,抛出异常,交给别人处理
-
作用:
当方法内部抛出异常时,我们必须处理这个异常
可以使用throws关键字处理异常对象,会把异常对象的抛出给方法的调用者处理(自己不处理,交给别人处理),最终交给JVM中断处理 -
格式 :在方法声明时处理
修饰符 返回值类型 方法名(参数列表) throws XxxException,YyyException{
throws new XxxException("产生原因");
throws new YyyException("产生原因");
}
-
注意事项:
- 必须写在方法声明处
- throws后面声明的异常必须是Exception及其子类
- 方法内部如果抛出了多个异常,throws后面也必须声明多个异常
如果多个异常对象有子父类关系,那么直接声明父类异常即可
- 调用了一个声明抛出异常的方法,我们就必须处理声明的异常
要么继续抛出异常,交给方法的调用者处理,最终交给JVM
要么try…catch捕获异常 -
throw和throws的区别
- throw
1. 用在方法体内,跟的是异常对象名
2. 表示抛出异常,由方法体内的语句处理
3. 执行 throw 一定抛出了某种异常 - throws
1. 用在方法声明后面,跟的是异常类名
2. 表示抛出异常,由该方法的调用者来处理
3. 表示出现异常的一种可能性,并不一定会发生这些异常
- throw
4.捕获异常try…catch
异常的第二种处理方式,捕获异常,自己处理异常
- 格式
try {
可能出现异常的代码;
} catch(异常类名1 变量名) {
异常处理代码;
//一般在工作中,会把异常的信息记录到一个日志中
}
//catch中子类异常放在父类异常的上面
...catch(异常类名n 变量名){
异常处理代码
}
- 注意事项
- try…catch可能抛出多个异常对象,那么就可以使用多个catch来处理这些异常
- 如果try中产生了异常那么就会执行catch中的异常处理逻辑,执行完毕catch继续执行try…catch之后的代码块
- 如果try中没有产生异常就不会执行catch中的异常处理逻辑,执行try…catch之后的代码
5.finally代码块
有些代码时无论如何都想要执行,就可以写在finally代码块中,比如释放资源
- 格式
finally 代码块
try {
可能出现异常的代码;
} catch(异常类名1 变量名) {
异常处理代码;
} catch(异常类名2 变量名) {
异常处理代码;
}finally{
无论是否出现异常都会执行
}
-
注意事项
- finally不能单独使用 必须和try…catch一起使用
- finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要资源释放(IO)
-
try…catch finally中return的执行顺序
-
在try和catch中有return
先finally,再return,但是catch返回值不变 -
在try和catch中有return,finally中也有return
try或catch中return后面的代码会执行,但最终返回的结果为finally中return的值,需要注意的是try或catch中return后面的代码会执行,只是存起来了,并没有返回,让finally捷足先登先返回了
//一般不推荐在finally里添加return
-
-
final finally finalize区别
- final 最终的,可修饰类,方法,属性
类:不能被继承
方法:不能被重写,可以被继承
属性:全局变量:声明是必须初始化。局部变量:声明的时候可以不初始化。但都只能赋值一次 - finally 跟try/catch后面,无论是否发生异常都会被执行。关闭数据库,关闭数据流。
- finalize 由系统调用,垃圾回收器回收之前做一些清理的工作。
- final 最终的,可修饰类,方法,属性
6.异常处理注意事项
- 多个异常捕获处理
- 多个try…catch分别处理
- 多个异常一次try,多次catch
catch里定义的异常如果有父子类关系,子类的异常必须写在上面,否则报错 - 多个异常一次try一次catch
运行时异常被抛出可以不处理。即不捕获也不抛出
默认会给JVM处理–中断程序
- 子父类异常
-
如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者不抛出父类的异常
-
父类没有抛出异常,子类重写父类方法时也不可以抛出异常,只能捕获处理,不能声明抛出
-
总结:父类的方法没有抛出的异常,子类重写父类的该方法不能抛出异常,只能捕获处理
-
三、throwable类自定义异常
1.常见方法
- String getMessage() 返回throwable的简短描述
- String toString() 返回throwable的详细消息字符串(比3详细)
- void printStackTrace() JVM打印异常(默认调用该方法),完整打印异常消息
2.自定义异常
java提供的异常类不够使用,可以自定义异常类
- 格式
继承Exception类
public class XxxException extends Exception{
添加一个无参构造方法
添加一个带有异常信息的构造方法
}
- 注意
- 自定义异常一般以Exception结尾,说明是一个异常类
- 必须继承Exception或者RuntimeException类
- 继承RuntimeException,无需处理交给JVM
- 继承RuntimeException,如果方法抛出了编译时异常,就必须处理
四、Debug追踪
1.Debug调试程序
可以让代码逐行执行,查看代码的执行过程,调试程序中出现的bug
2.使用方式
在行号的右边,鼠标左键单击添加断点(在每个方法的第一行,哪里有bug添加哪里)
右键Debug运行 程序会停留在添加的第一个断点处
3.执行程序
F8: 逐行执行
F7: 进入到方法中
shift+F8: 跳出方法
F9: 跳到下一个断点,如果没有断点则结束程序
ctrl+F2 退出Debug