Java - 异常
一、异常概述
- 异常 :指的是程序在执行过程中,出现的非正常的情况,如果不处理最终会导致JVM的非正常停止,并不是指的语法错误
- 正确对待异常:编写程序时,应该充分考虑到各种可能发生的异常和错误,极力预防和避免,实在无法避免的,要编写相应的代码进行异常的检测、异常消息的提示,以及异常的处理
- 异常的抛出机制:Java中把不同的异常用不同的类表示,一旦发生某种异常,就通过创建该异常类型的对象,并且抛出。程序可以catch到这个异常对象并处理,如果无法catch到这个异常对象,那么这个异常对象将会导致程序终止
二、异常体系
1、Throwable
java.lang.Throwable
类是 Java 语言中所有错误或异常的超类。只有当对象是此类或其子类的实例时,才能通过Java虚拟机或者Java的throw
语句抛出Throwable中的常用方法:
public void printStackTrace()
:打印异常的详细信息(包含了异常类型、异常原因,异常出现的位置)public String getMessage()
:获取发生异常的原因(提示给用户的时候,就提示错误原因)
2、Error和Exception
Throwable
有两个直接子类:java.lang.Error
与java.lang.Exception
- Error:表示严重错误,一旦发生必须停下来查看问题并解决问题才能继续,无法仅仅通过try…catch解决的错误,例如:
StackOverflowError
(栈内存溢出)和OutOfMemoryError
(堆内存溢出,简称OOM) - Exception:表示普通异常,其它因编程错误或偶然的外在因素导致的一般性问题,可以通过代码的方式检测、提示和纠正,使程序继续运行,但是只要发生也是必须处理,否则程序也会挂掉,例如:空指针访问、试图读取不存在的文件、网络连接中断、数组下标越界等
- Error:表示严重错误,一旦发生必须停下来查看问题并解决问题才能继续,无法仅仅通过try…catch解决的错误,例如:
三、受检异常和非受检异常
平常说的异常就是指
Exception
,可以将异常分为:- 编译时期异常(即checked异常、受检异常):在代码编译阶段,编译器就能明确警示当前代码可能发生异常,如果没有编写对应的异常处理代码,则会编译失败,从而程序无法执行。例如:
FileNotFoundException
(文件找不到异常) - 运行时期异常(即runtime异常、unchecked非受检异常):即在代码编译阶段,编译器完全不做任何检查,无论该异常是否会发生,编译器都不给出任何提示。只有等代码运行起来才能被发现。通常,这类异常是由代码编写不当引起的。例如:
ArrayIndexOutOfBoundsException
数组下标越界异常,ClassCastException
类型转换异常。
- 编译时期异常(即checked异常、受检异常):在代码编译阶段,编译器就能明确警示当前代码可能发生异常,如果没有编写对应的异常处理代码,则会编译失败,从而程序无法执行。例如:
四、异常的生成
异常对象的生成有两种方式:
- 由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,就会在后台自动创建一个对应异常类的实例对象并抛出
- 手动创建,格式:
throw new 异常类名(实参);
如果是编译时异常类型的对象,则需要处理异常,否则编译不通过
如果是运行时异常类型的对象,编译器不会提示
throw语句是明确抛出一个异常对象,因此它下面的代码将不会执行,如果当前方法没有try…catch处理这个异常对象,throw语句就会代替return语句提前终止当前方法的执行,并返回一个异常对象给调用者
四、异常的处理
1、捕获异常try…catch
- try…catch基本格式
1 | try{ |
- JDK1.7之后try…catch新特性:如果多个catch分支的异常处理代码一致,支持如下写法
1 | try{ |
- 如果有多个catch分支,并且多个异常类型有父子类关系,必须保证子异常类型在上,大父异常类型在下
- 可以使用Throwable类中的方法,在catch分支中获取异常信息
2、finally块
因为程序中有一些特定的代码无论异常是否发生,都需要执行(例如,IO流的关闭,数据库连接的断开等),这样的代码通常就会放到finally块中
两种形式
- 形式一:
try...catch...finally
,此时无论try中是否发生异常,也无论catch是否捕获异常,也不管try和catch中是否有return语句,都一定会执行 - 形式二:
try...finally
,无论try中是否发生异常,也不管try中是否有return语句,都一定会执行
- 形式一:
当只有在try或者catch中调用退出JVM的相关方法时,才会不执行
3、转换异常处理位置throws
- 在编写方法体的代码时,某句代码可能发生编译时异常,但是在当前方法体中可能不适合处理或无法给出合理的处理方式,就可以通过throws在方法签名中声明该方法可能会发生xx异常,需要调用者处理
- 声明异常格式:
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{}
throws后面也可以写运行时异常类型,如果写了,唯一的区别就是调用者调用该方法后,使用try…catch结构时,IDEA可以获得更多的信息,需要添加什么catch分支
对于带throws的方法重写的特殊要求
- 不能是
static
,final
修饰的方法 - throws异常列表要求
- 不能是
- 如果父类方法签名后面没有
throws 编译时异常类型
,那么重写方法时,方法签名后面也不能出现throws 编译时异常类型
,反之,需要是父类异常类型的子类
- 如果父类方法签名后面没有
- 对于
throws 运行时异常类型
没有要求
- 对于
throws是方法可能抛出异常的声明(表示该方法可能要抛出异常)
五、自定义异常
定义格式:
- 编译时异常类型:自定义类,并继承
java.lang.Exception
- 运行时异常类型:自定义类,并继承
java.lang.RuntimeException
- 编译时异常类型:自定义类,并继承
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 妙妙屋!