文章目录
异常
表示java程序运行中的错误(信息)
java异常处理机制的由来
- C语言时代的错误处理(程序员自觉处理)
- java的基本理念:
运行之前发现错误,但是有一些错误是编译器发现不了的错 - 错误恢复机制(java异常处理机制)
允许出错,但是一旦出错,有办法感知到这个错误并且进行补救。
将错误向上报告。上级知道怎么处理错误就可以在语言层面自己处理这个错误,如果上级也不知道怎么处理的时候则将错误继续向上报告。最终报告给了jvm,
jvm有默认的处理方式
1、当代码在执行到发生错误的地方,
2、jvm会终止当前的程序,转入错误处理流程
3、在发生错误的地方,收集错误信息,产生一个描述错误的对象(异常对象)
4、访问收集到的信息,将错误的信息输出到控制台窗口中
jvm异常的分类
Exception:在程序中可能能够处理的错误
- 编译时异常(Checkable Exception)
可以预见的,语法层面强制在代码编写时处理
本身代表的是编译时异常,他的直接子类也表示编译时异常(除了RunTimeException) - 运行时异常(RunTime Exception)
本身代表的是运行时异常,他的直接子类也表示运行时异常
不可预见的,不要求在编写代码时必须处理
区别
运行时异常
无需显示处理,也可以和编译时异常一样处理
编译时异常
Java程序必须显示处理,否则程序就会发生错误
无法通过编译
Error:
在程序层面无法处理的错误(致命的错误)
异常处理的语法
try{
//可能出现异常的,正常的代码逻辑
}catch(){//catch又叫异常处理器
//每一个catch分支对应一个异常处理器
//在catch分支中处理具体类型的代码异常
//错误记录到日志文件中
}
多分支异常匹配
-
当在tru{}可能产生多种异常,但是在实际中,尝试不同的异常有不同的处理方法,所以定义多个catch,各司其职
1、在catch(ArithmeticException e)
2、在catch(ArrayIndexOutOfBoundsException e)
3、在catch(NullPointerException e) -
如何区分不同异常分支(异常处理器)呢? 根据异常处理器所声明的不同的异常处理类型来区分, jvm 怎么知道,把异常对象交给哪个异常分支,并执行那个异常分支中的代码,这就存在一个多分支异常处理的匹配问题:
1.根据实际的异常对象的类型,和异常分支(异常处理器)声明的异常类型,从上到下一次做类型匹配
2.一旦通过类型匹配,发现实际异常对象的类型和Catch分支(异常处理器)声明的异常类型,类型匹配,就把异常对象交过
这个异常分支(异常处理器)
3.多分支的异常处理的执行,有点类似于多分支if-else的执行,一次匹配,只会执行多个catch分支中的一个-
注意事项:
1如果说,在多catch分支的情况下,如果不同的catch分支,处理的异常类型,有父子关系,那么就一定要注意,处理子类的异常分支写在前面,父类的异常分支写在后面2不是包裹在try块中的代码,一旦产生了异常,都是自己来处理,只有try中异常类型, 有对应类型的异常处理器的时候
-
-
catch处理多分支语法
-
catch(xxxx|xxxx|xxxx){}
获取异常信息
getMessage()
获取异常信息,返回字符串。
toString()
获取异常类名和异常信息,返回字符串。
printStackTrace()
获取异常类名和异常信息,以及异常出现在程序中的位置,
并打印到控制台
printStackTrace(PrintStream s)
该方法将异常内容保存在日志文件中,以便查阅。
在Java中,与异常抛出有关的主要有两个关键字:
throws
在方法定义时使用
声明该方法可能抛出的异常
对于编译时异常,可以在语法层面强制方法调用者处理该异常
基本语法:
修饰符 返回值(形参列表) throws 异常列表 {}
注意事项:
异常列表之间用逗号分割,列表中出现的异常不要出现包含父子关系
方法覆盖时的子类异常列表必须与父类兼容
a. 当子类方法声明的异常类型和父类声明的异常类型,完全相同的时候,可以发生方法覆盖
b. 子类中声明的异常类型, 都是父类中声明异常列表中的异常的子类类型(只针对编译时异常)
c. 如果说父类没有异常列表,对于 编译时异常 而言,子类也不能有异常列表(子类也没有才能发生方法覆盖)
d. 如果说父类有异常列表,子类没有异常列表,不管是编译时异常,还是运行时异常,都可以发生方法覆盖
throws VS throw
- throws
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常 - throw
用在方法体内,跟的是异常对象名
只能抛出一个异常对象
表示抛出异常,可以由方法体内的语句处理
throw则是抛出了异常,执行throw则一定抛出了某种异常
finally代码块
finally的特点
被finally控制的语句体一定会执行
特殊情况:在执行到finally之前jvm退出了(比如System.exit(0))
finally的作用
用于释放资源,在IO流操作和数据库操作中会见到
finally相关的面试题
- final,finally和finalize的区别
final用于声明属性,方法和类,分别表示属性不可交变,方法不可覆盖,类不可继承。
finally是异常处理语句结构的一部分,表示总是执行。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,供垃圾收集时的其他资源回收,例如关闭文件等。 - 如果catch里面有return语句,请问finally的代码还会执行吗?
如果会,请问是在return前还是return后
会执行,但是return与finally并没有明显的谁强谁弱。在执行时,是return语句先把返回值写入但内存中,然后停下来等待finally语句块执行完,return再执行后面的一段。
try…catch…finally可以使用
try…catch也可以使用
try…finally也可以使用
但是,catch,finally不能单独使用
。