异常的概念
Java异常是Java提供的用于处理程序中非正常情况的一种机制
Java异常处理的关键字有throws声明抛出异常、throw编程抛出异常、try定义陷阱代码、catch捕获异常进行处理、finally无论正常执行还是出现异常都需要执行的代码
共5个关键字
异常的分类
JavaSE中定义了很多异常类,这些类可以对应各种各样可能出现的异常事件。
Throwable类是Java异常类型的顶层父类,一个对象只有是 Throwable 类的(直接或者间接)实例,他才是一个异常对象,才能被异常处理机制识别
Java异常可以分为3大类 [面试点 ]
- Error及其子类:错误,一般指的是虚拟机的错误,是由Java虚拟机生成并抛出,程序不能进行处理所以也不加处理,例如OutOfMemoryError内存溢出、调用栈溢出StackOverFlowError
- RuntimeException及其子类:运行时异常(非受检型异常),是由于编程bug所导致,希望越早发现越好,所以不进行处理,直接中断报错即可,编程人员针对报错信息修改程序bug来解决问题
常见的运行时异常:- ArithmeticException算术异常
- NullPointerException空指针异常
- IndexOutOfBoundsException下标出界
- ClassCastException类/类型转换异常
- NumberFormatException数据格式异常
- Exception及其子类中除了RuntimeException及其子类之外的其它异常:受检型异常(非运行时异常),这类异常属于明知道可能出现,但是没有办法杜绝的异常。这类异常一般采用try/catch进行异常处理,当程序出现了非正常情况,尽量保证程序正常结果,而不是立即中断
异常的捕获和处理
try{
//try代码段中包含可能产生异常的代码,有人称为陷阱代码
} catch(SomeException e){
//try后可以跟一个多个catch代码段,针对不同异常执行不同的处理逻辑。当异常发生时,程序会中止当前的流程,根据获取异常的类型去执行相应的代码段。注意异常类型判定时是从上向下逐个判断的。
}finally{
//finally代码是无论是否发生异常都会执行的代码
}
注意:
- try块中的局部变量和catch块中的局部变量(包括异常变量),以及finally中的局部变量,他们之间不可共享使用
- Java采用的是终结式异常处理机制,java中异常处理的任务就是将执行控制流从异常发生的地方转移到能够处理这种异常的地方去。也就是说:当一个函数的某条语句发生异常时,这条语句的后面的语句不会再执行,它失去了焦点。执行流跳转到最近的匹配的异常处理catch代码块去执行,异常被处理完后,执行流会接着在“处理了这个异常的catch代码块”后面接着执行。
常见的3种输出异常的用法
- System.out.println(e)实际上调用的是e.toString()
java.lang.NumberFormatException: For input string: "123.456"
异常的类型名称 : 异常的说明信息
- e.getMessage()
For input string: "123.456"
- e.printStackTrace()
考核点:finally块和return
返回值不管是否异常都是finally中的return
考点:finally、final和finalize的区别
finally用于try/catch/finally结构中主要用于定义最终必须执行的逻辑(不管是否 出现异常都会被执行)
final用于修改类(表示该类不允许继承)、属性(表示一旦赋值不允许修 改)、局部变量(表示一旦赋值不允许修改)、方法(表示方法不能被覆盖)
finalize是析构器方法名称,在对象被垃圾回收之前所执行的处理逻辑,理论上来说应该进行对象中所使用资源的回收,但是由于gc的运行时机不确定,一般编码中不使用它进行资源回收
最佳异常相关编程实践
- 不要在finally中使用return
public int pp(){
int res=0;
try{
.... res=100;
}catch(Exception e){
.... res=200;
}finally{
.... res=300;
}
return res;
}
- 不要在finally中抛出异常
- 减轻finally的任务,不要在finally中做一些其它的事情,finally块仅仅用来释放资源是最合适的
- 尽量将所有的return写在函数的最后面,而不是try …catch …finally中
自定义异常
通过继承java.lang.Exception类声明自定义异常类[也允许继承Throwable或者Exception的子类]
public class MyException extends Exception{}
- 一个无参构造函数
public MyException(){
//super(); 调用父类的构造器完成异常对象的初始化操作
super("账户不存在");//参数就是异常的相关信息 getMessage()
}
- 一个带有String参数的构造函数,并传递给父类的构造函数。
public MyException(String msg){
super(msg); //getMessage()
}
- 一个带有String参数和Throwable参数,并都传递给父类构造函数
public MyException(String msg,Throwable throwable){
super(msg,throwable);
}
- 一个带有Throwable 参数的构造函数,并传递给父类的构造函数
public MyException(Throwable throwable){
super(throwable);
}
如果自定义异常是通过继承受检型异常实现的,则需要针对异常进行处理。1、使用try/catch进行处理。2、使用throws声明继续向上抛出
异常处理建议规则
- 不要过度使用异常,不要把异常当做不同的逻辑分支对待
- 不要使用过于庞大的try块
- 避免使用catch all语句try{}catch(Throwable t){}
- 坚决不要忽略捕获的异常,不允许catch块中内容为空