1.异常类的体系结构
2.异常的处理方式
try-catch-finally
发生异常时进行捕获,并在catch中处理(程序执行的焦点从try中转移到catch中)
- 多个catch块时,catch中的异常参数不共享
- catch中捕获异常后,仍然可以将该异常继续向上抛出
//例如:异常在方法A中正常处理,调用A方法时需要对异常计数
catch(Exception e){
//异常处理逻辑
...
//向上抛出
throw e;
}
- 子类异常放在前面,否则报错并提示
异常已被处理
- Java中,异常发生时,异常之后的代码不继续执行,程序焦点转移到catch代码块中(终结式异常处理模式)
- 恢复式异常处理模式:异常处理后,执行流会恢复到异常抛出点之后继续执行
- java中异常是线程独立的,不会影响到其他线程,只能由线程内部自己解决
throws
将异常向调用者声明,而自己不进行处理
- 若父类中throws异常,则子类只能抛出相同或比父类”低“的异常。为了支持多态,
处理父类异常的处理器必须同样能够处理其所有子类throws的异常
throw
- 手动抛出一个异常,其后必须是一个异常对象
- 与JRE抛出的异常一样,throw的地方叫异常抛出点
finally详解
- 不管异常是否发生,finally都会执行,除非
System.exit();
- finally没有异常处理能力,处理异常的是catch代码块
- 当catch处理异常时也发生异常,finally同样执行
- finally 中
使用return
,会覆盖 try 、catch中的返回值 - finally 与try或catch同时发生异常时,会覆盖 try、catch中的异常,即只能显示finally中的异常
3.自定义异常
为什么要自定义异常:使用Java异常捕获机制,当出现异常时,我们可以让程序按照要求继续执行,即在catch代码块中做处理。当方法执行过程中出现不同情况的异常时,我们希望程序做对应处理,但在catch中捕获Exception表示对所有异常做统一处理,显然这不是我们想要的,因此我们需要自定义异常,并在catch代码块中捕获自定义异常,并给出此类异常的解决逻辑。
- 根据需要,继承Exception 或 RuntimeException
- 自定义异常的构造函数模板如下:
public class XException extends Exception{
//无参
public XException(){
super();
}
//单参 msg
public XException(String msg){
super(msg);
}
//单参 throwable
public XException(Throwable cause){
super(cause);
}
//双参 msg,throwable
public XException(String msg,Throwable cause){
super(msg,cause);
}
}
4.异常链化
- 将异常对象作为参数传入构造新的异常对象。调用过程中,不止一处发生异常时,
异常信息不会被覆盖,异常根源信息不会丢失 - 包装自定义异常时,为了异常链不断,将异常作为参数传入
catch(XXException e){
//手动抛出的异常中传入了e,异常的堆栈信息中将包含XXException的相关信息
throw new ZZException("message",e);
}
5.java中使用异常的几个原则
- 尽量不要捕获通用异常,应捕获特定异常
- 扩散RuntimeException,而不是被捕获
- 不要生吞异常(swallow)
- 生产环境不要使用打印堆栈(e.printStackTrace)
- throw early,catch late 原则
- 它往往会影响 JVM 对代码进行优化,所以建议仅捕获有必要的代码段,尽量不要一个大的 try 包住整段的代码