异常
一. 异常概述
1. 异常的概述
异常就是程序出现了不正常的情况,在程序在执行过程中,出现的非正常的情况,最终会导致程序非正常停止。
需要注意:语法错误不算在异常体系中。
2. 异常体系结构
在java中异常使用类进行描述,使用的时候使用类的对象来体现具体的异常。java的异常体系其实就是类的体系关系网。
java大部分的异常jdk已经给描述好,可以直接拿来实例化使用 (jvm会异常封装一个对象给程序员抛出来)。只有特殊的情况下可以人为自定义异常类,供自己或他人使用
1.Throwable
可抛出的,是异常体系的顶层父类,其他的异常或者错误都是Throwable的子类类型,只有Throwable的体系类型,才可以使用异常的处理机制。才能被JVM或者throw关键抛出.
2.Error
错误,是Throwable的子类,用于描述那些无法捕获和处理的错误情况,属于非常严重的错误.StackOverflowError Exception Throwable的子类,用于描述那些可以捕获和处理的意外情况,属于不太严重的错误。
3.RuntimeException
及其子类运行时异常,是Exception的特殊的子类,在编译阶段不做检查的一类异常(出现和不出这种异常没有任何区别, 处理不处理都行)。如:ArrayIndexOutOfBoundsException
4.除RuntimeException之外所有的异常类
编译时异常,是Exception的子类们,在编译阶段就会检查的一类异常(有这种异常出现,就必须处理,不处理程序无法编译通过)。比如:ParseException
3.异常处理方式
捕获式异常:使用代码把具体的异常捕获到,把异常处理掉的方式,程序运行时如果真的出现异常了,还能继续 执行.
声明式异常:不使用代码捕获具体的异常,使用代码告诉下一个使用者有异常你要处理, 程序运行时如果真的
出现异常了,程序停止,无法继续向下执行.
1) try…catch
格式:
try{
可能有异常的代码1
可能有异常的代码2
可能有异常的代码3
}catch(异常类型 变量){
处理具体异常的方案
}
格式解释:只能捕获处理一个异常
try :尝试 尝试的诊断有可能产生异常的代码
catch :捕获 try 当中的代码哪里产生了异常到哪里捕获具体的异常对象到异常变量中 处理方案:当捕获到具体的异常时要去执行的代码
执行流程: 1、执行诊断try中有可能发生异常的代码
没有异常:跳过catch以及异常方案 继续执行后续代码
有异常产生: catch 到有异常的部位捕获具体的异常对象回处理方案
执行处理方案之后跳出try...catch 继续执行后续代码
2)try…catch…catch
格式:
try{
可能有异常的代码1
可能有异常的代码2
可能有异常的代码3
}catch(异常类型1 变量1){
处理具体异常的方案
}catch(异常类型2 变量2){
处理具体异常的方案 } ......
catch(异常类型n 变量n){
处理具体异常的方案
}
执行流程: 先执行诊断try有可能发生异常的代码段
无异常:跳过所有的catch和方案执行后续的代码段
有异常: 使用和第一个发生的异常对象类型相匹配的类型的catch进行捕获具体的异常对象执行对应的处理方案跳 出整个try...catch...catch结构执行后续代码
注意事项:
1、多异常有可能同时发生的时候捕获的时候只捕获第一个发生的异常
2、即使写了多个catch语句,但是也有产生的异常不能捕获,如果出现了,程序依然会停止.
3、多个catch块中的异常变量类型如果没有继承关系,顺序随意书写,如果有子父类继承关系子类必须在前父类在后
3) try…catch…finally
格式:
try{
可能有异常的代码
}catch(异常类型1 变量1){
处理具体异常的方案
}catch(异常类型2 变量2){
处理具体异常的方案
} ...... catch(异常类型n 变量n){
处理具体异常的方案
}finally{
无论是否发生异常都必须执行的代码
}
执行流程: 1、尝试诊断try里面的代码段
有异常:使用对应的catch块捕获 异常对象执行对应的处理方案执行finally的代码
没有异常:跳过所有的catch块执行finally中的代码
特点:1.处理异常的基础上增加对必须要执行的代码的处理
2.finally 中代码无论是否有异常发生都要执行,必须借助捕获处理的格式
3.try中有异常产生,多个catch没有捕获到,finally也会执行.
4.在try中写了return, finally中内容也会执行了.
注意事项:
finally 不能单独使用,在IO作用经常用来【关闭流】
4) try…finally
格式:
try{
可能发生异常的代码段
}finally{
必须要执行的代码
}
执行特点: 先执行try中代码
无异常: 执行finally代码块,结束后执行后面的代码
有异常: 执行finally代码块,程序就会停止,后面的代码无法执行.
作用:单独为了执行必须要执行的代码,以后如果你有两段代码,不想因为前一段代码执行成功与否,影响到第二 段的执行.就可以把第一段代码放到try中,第二段放到finally中.
注意:
try...finally 没有处理任何的捕获异常能力, 一旦有异常产生程序就会非正常停止, 但是也会保证
finally中代码必然执行.
捕获处理异常的注意事项
1、catch块的异常类型书写:
没有子父类关系顺序随意
有子父类关系子类在前父类在后【自小而大】
2、finally不可以单独使用
3、如果多个catch块的处理方案一致,可以合并
1、使用父类类型变量捕获
2、类型使用逻辑或链接【前提:多个类型没有继承关系】
4、try 和 catch 也不能单独使用
声明处理Throws
概述:
遇到异常自己不做具体的处理方案,使用关键字 throws 把异常的类型声明出去【抛出去】,声明给 下一个使用该方法的元素
方式:
在方法的参数列表【声明】后使用 throws + 异常的类型1,异常的类型2, 异常的类型3...
比如: public static void test() throws ParseException {}
虽然处理异常比较简单,缺点出现异常程序会非正常停止.导致后面的代码无法执行.如果以后咱们想出了问题 还能继续执行,就不用thorws方式处理异常,而是用 try..catch
异常的注意事项
- 运行时异常抛出可以不处理,既不捕获也不声明抛出。【实际开发一般不处理】
- 如果父类,方法抛出了多个编译时异常,子类覆盖父类的方法时,可以不抛出异常,或者抛出
- 相同的异常,或者父类抛出异常的子类。
- 如果父类方法没有异常抛出,子类覆盖父类方法时,不能抛出编译时异常。
二. throw关键字
- 概述
throw 是一个关键字,抛出的意思,代码产生了一个具体的异常对象的时候,用来抛出该异常对象的一个关键字 使用在方法的方法体中. 也就是使用throw就可以自己抛出异常对象了.
- 格式:
修饰符 返回值类型 方法名(参数列表){
throw 异常对象;
}
- 作用
抛出具体的异常对象
抛出的是运行时异常对象 可处理可不处理.
抛出的是编译时异常对象 必须处理【声明可以或者捕获也可以】
- throw 和throws的区别
throws | throw | |
---|---|---|
位置 | 用在方法声明(参数列表)后面,跟的是异常名 | 用在方法体内,跟的是异常对象 |
作用1 | 表示声明异常,调用该方法有可能会出现这样的异常 | 表示手动抛出异常对象,只要语句执行必然有异常抛出 |
作用2 | 用来处理异常 | 用来产生异常对象 |
JVM的默认处理异常的方式
- 概述
1、在代码的某个位置,出现了和正常情况不同的情况,JVM就将异常情况封装到一个异常对象中。
2、将异常对象抛给调用该方法的方法
3、某个方法接收到底层方法抛上来的异常,也没有办法自己处理,继续向上抛出,最终抛给主方法,主方法
也没有办法处理,抛给调用自己的jvm虚拟机
4、jvm虚拟机是我们手动调用的,只能将异常对象的所有信息,通过错误流打印出来,结束jvm虚拟机
5、总结,jvm默认处理的方式:【一层一层向上抛,jvm接收到之后结束自己,捕获处理】
Throwable的常用方法
- Throwable构造方法
1、Throwable():创建一个没有任何信息异常对象
2、Throwable(String message):创建一个具有描述异常信息的异常对象
3、Throwable(Throwable t):创建一个具有异常原因信息的异常对象
- 常用方法
1.public String getMessage() //返回此 throwable 的详细消息字符串
2.public String toString() //返回此可抛出的简短描述【对象的名称 原因 描述信息】
3.public void printStackTrace() //把异常的错误栈轨迹信息输出在控制台【】
4.public Throwable getCause() //获取异常对象的产生原因
异常注意事项
1.运行时异常抛出可以不处理,既不捕获也不声明抛出。【实际开发一般不处理】
2.如果父类(接口)方法抛出了多个编译时异常,子类覆盖(重写)父类(接口)的方法时,可以不抛
出异常,或者抛出相同的异常,或者父类抛出异常的子类。 子类不能抛出比父类方法更大异常.
3.如果父类(接口)方法没有异常抛出,子类覆盖父类(接口)方法时,不能抛出编译时异常。
自定义异常的使用
- 自定义异常概述
1.当Java中提供的异常不能满足我们的需求时,我们可以自定义异常类。
2.类要想成为异常类必须得成为异常体系的一员,需要继承异常体系中的某个类。
3.异常无非就编译时异常和运行时异常,定义的时候只需要设计自己类继承代表整个编译时异常类或运行时异常的类.来决定自己定义的那种异常.
Exception:代表整个编译时异常
RunTimeException:代表整个的运行异常
- 实现步骤
1.设计异常列名,要让自己的类名也要见名知意. XxxYyy+Exception
2.定义一个类继承对应的父类【编译异常:Exception 运行异常: RunTimeException】
3. 提供空参构造即可 或者可传递异常信息的构造方法
编译时异常和运行时异常,定义的时候只需要设计自己类继承代表整个编译时异常类或运行时异常的类.来决定自己定义的那种异常.
Exception:代表整个编译时异常
RunTimeException:代表整个的运行异常
- 实现步骤
1.设计异常列名,要让自己的类名也要见名知意. XxxYyy+Exception
2.定义一个类继承对应的父类【编译异常:Exception 运行异常: RunTimeException】
3. 提供空参构造即可 或者可传递异常信息的构造方法