目录
9-1 异常的理解、体系结构
异常:程序执行过程中出现的非正常情况,不处理会导致jvm非正常停止工作
异常抛出机制:出现异常后,java会创建这种异常的对象并抛出,可以让程序员捕获
为什么要捕获:希望即使有问题也能把整个运行完,或者遇到问题时方便处理不影响整体运行
Java异常体系结构
Throwable是所有异常的根父类
public void printStackTrace():打印异常详细信息
public String getMessage():获取发生异常的原因
根父类的子类都可以用这个方法
Throwable可以分为Error和Exception两大类
分别对应java.lang.Error和java.lang.Exception
Error:称为错误,jvm无法解决的严重问题,不编写针对性代码处理
Exception:成为异常,一般是编程错误或者偶然因素造成的一半问题,需要用代码处理
异常处理针对的是Exception!
9-2 常见的运行时异常、编译时异常
两种异常表示在不同的时刻发生的错误
两个时刻:javac.exe进行编译(成为字节码文件)、java.exe进行运行
编译时期异常:即checked异常、受检异常
运行时期异常:即runtime异常、unchecked异常、非受检异常
如何区分:runtime异常类及其的子类都是运行时异常,除此以外的都是编译时异常
常见的错误与异常
Error错误:StackOverflowError(栈溢出)、OutOfMemoryError(OOM)
运行时异常:NullPointerException(空指针)、ClassCastException(类型转换异常)、ArrayIndexOutOfBoundsException(数组索引越界)、InputMismatchException(输入类型不匹配)、ArithmeticException(算术异常)、NumberFormatException(数字格式化异常)
编译时异常:ClassNotFoundException(未找到类)、FileNotFoundException(未找到文件)、IOException(IO流异常)
9-3 异常处理方式一:try-catch-finally
为什么要处理:在可能出现的地方写上预防异常
抓抛模型:try-catch-finally
一旦throw出了异常,后面的代码先不执行
模型语法:
try{
// 可能产生异常的代码
}
catch(异常类型1 e){ // 对应处理措施 }
catch(异常类型2 e){ // 对应处理措施 }
catch(异常类型3 e){ // 对应处理措施 }
……
finally{ // 无论是否异常都会执行的语句 }
一旦try中出现异常,会在几个catch里面由上至下的寻找对应的错误然后执行分支。如果找到了错误,那么try后续的代码就 不执行了。
如果抛出了异常单但都不匹配,那么会终止运行
catch的参数中的e为异常对象的名字
如果有多个catch且多个异常类型存在父子类关系(可以用Ctrl+H看继承关系),必须保证小的子异常在上,大的负异常在下,否则会报错
9-4 finally的使用说明
finally后面的语句:无论是否发生异常,都一定会执行的语句(一般放一些一定要执行的代码)
例外:使用System.exit(0)来终止当前正在执行的Java虚拟机
如果有return,也是有限在finally里的优先级最高,它优先于catch和try里面的return
特别:RuntimeException类或者子类的异常Java自己会捕获并且通过,但是非运行时异常则必须捕获否则编译错误
9-5 异常处理方式二:throws
针对编译时异常!
这个throws的s不要漏!
throws是显式地将声明抛出异常,表示此方法不对这些异常处理并让方法的调用者(上层)负责
如果main向上throws给OS则会导致程序终止,因为jvm无法处理异常,因而main不要throws
throws后面接的异常列表,可以使方法中产生的异常类型,也可以是这些类型的父类
基本格式:(用在方法声明中)
[修饰符] 返回值类型 方法名(参数) throws 异常类名1,异常类名2……{ }
重写方法:
如果父类被重写方法后面没有throws编译时异常类型,那么重写的方法也不能出现
如果后面有throws编译时异常类型,那么重写的方法throws的编译时异常类型必须 <= 原本的,或者不throws编译时异常类型(理解:表示子类抛出的异常最大是这些,不能超出父类的)
而如果throws后面是运行时异常类型,则无要求(但一般throws后面不接运行时异常,因为没区别)
9-6 手动抛出异常对象与自定义异常类
手动抛出/创建异常:throw new 异常类名(参数);这里throw没有s!!!
括号中的参数通常为字符串信息,这相当于是主动使用throw,用做提示方便打印异常情况(这种错误一般是看场景的,而不是代码本身的异常)
就算是throw new,也需要用抓抛模型进行捕获、处理
如果没有try-catch,那么throw会代替return提前终止运行并且返回一个异常对象
自定义异常:根据业务需求自定义异常情况
1、继承一个异常类型,可选Exception和Runtime(后者可不处理)
2、最好提供两个构造器,一个无参,一个(String message)
3、要提供serialVersionUID作为唯一标识,在类中为静态常量
4、写的时候按照整个的类来写
注意:自定义的异常只能通过throw抛出,然后由try-catch处理,或者用throws继续向上甩锅
标识符UID一般是long类型的整数,随便找一个现有的然后随便改改就可以使用了