主题
java 的异常体系
一、java 中的异常分为哪几类?

1.Exception:出现的问题是可以被捕获的;
1.check 异常: 直接派生自 Exception 的异常类,必须被捕获或再次声明抛出
2.runtime 异常:派生自 RuntimeException 的异常类。使用 throw 语句可以随时抛出这种异常对象
2.Error:系统错误,通常由 JVM 处理。
二、异常的处理机制有几种?
1、异常捕捉
try-catch 语句或者 try-catch-finally 语句实现
2、异常抛出
throws 异常抛出:
throws 语句用在方法定义时声明该方法要抛出的异常类型,如果抛出的是 Exception 异常类型,则该方法被声明为抛出所有的异常。多个异常可使用逗号分割。throws 语句的语法格式为:
java
methodname throws Exception1,Exception2,..,ExceptionN
{
}Throws 抛出异常的规则:
1) 如果是不可查异常(unchecked exception),即 Error、RuntimeException 或它们的子类,那么可以不使用 throws 关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。(不需要 catch 或者 throws 处理抛出的异常就是 unchecked 异常)
2)必须声明方法可抛出的任何可查异常(checked exception)。即如果一个方法可能出现受可查异常,要么用 try-catch 语句捕获,要么用 throws 子句声明将它抛出,否则会导致编译错误
3)仅当抛出了异常,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出,而不是囫囵吞枣。
4)调用方法必须遵循任何可查异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。
结论:
finally 如果有 return 会覆盖 catch 里的 throw,同样如果 finally 里有 throw 会覆盖 catch 里的 return。
进而如果 catch 里和 finally 都有 return, finally 中的 return 会覆盖 catch 中的。throw 也是如此。
三、如何自定义一个异常
1、第一步:编写一个类,继承 Exception,或者继承 RuntimeException,看你是自定义编译时异常,还是自定义运行时异常;
2、第二步:提供两个构造方法,一个无参数构造方法,一个带有 String s 参数的。有参数方法体中写 super(s) 即可。
例:
java
public static void main(String[] args) {
// 创建自定义异常类的实例,并不抛出
MyStackOperatorException e = new MyStackOperatorException("栈操作有误");
String msg = e.getMessage();
System.out.println(msg); // 栈操作有误
e.printStackTrace(); // exception.MyStackOperatorException: 栈操作有误 }
}
// 自定义异常类
public static class MyStackOperatorException extends Exception {
public MyStackOperatorException() {
}
public MyStackOperatorException(String s) {
super(s);
}
}四、Throw 与 Throws 的区别
1、Throw 用于方法内部,Throws 用于方法声明上
2、Throw 后跟异常对象,Throws 后跟异常类型
3、Throw 后只能跟一个异常对象,Throws 后可以一次声明多种异常类型
五、Error 与 Exception 区别
1、Exception 和 Error 继承 Throwable 类,在 java 中只有 Throwable 类型的实例才能被抛出 (throw) 或者捕获 (catch),他是异常处理机制的基本类型。
2、Exception 和 Error 体现了 java 平台针对不同异常情况的分类。Exception 是程序正常运行过程中,可以预料的意外情况,可能并且应该被捕获,并进行处理。Error 正常情况下不大可能出现的情况,绝大部分的 Error 都会导致程序状态不正常,不可恢复,既然是非正常情况,所以不便也不需要处理,例如 OutOfMemoryError 之类都是 Error 的子类
3、Exception 分为检查型异常和非检查型异常。检查型异常必须在源码中进行捕获处理,这是编译检查的一部分。除了 RuntimeExceion 及其子类之外的异常都是检查型异常。非检查型异常就是所谓的 RuntimeExceion,类似 NullPointerException,ArrayIndexOfBoundException 就是非检查型异常,通常是可以通过编码避免的逻辑错误,具体根据需要判断是否需要捕获,编译期不检查,如果抛出了非检查型异常,那就是编码逻辑有问题,要解决。
六、如何处理异常
1、直接抛出
java
public static void main(String[] args) throws FileNotFoundException {
try {
InputStream inputStream = new FileInputStream(new File(""));
}catch (Exception e){
}
}2、异常处理两种方式:catch 住本身( 对于本身可预测的异常 你就可以 catch 住具体的异常 ) 或 catch 父类(无法预测抛出什么异常 ,就可以 cathc 主异常的父类 Exception)
java
public void handleExceptionOne() throws FileNotFoundException {
//抛出异常 交由调用此方法的人处理
InputStream inputStream = new FileInputStream(new File(""));
}
public void handleExceptionTwo() {
//catch主异常本身
try {
InputStream inputStream = new FileInputStream(new File(""));
}catch (FileNotFoundException e){
//务必打印异常信息 项目中log.error 或者是 log.warn() 根据具体业务区分
//
e.printStackTrace(); //本地测试可用这个
log.error("FileNotFoundException:", e);
}
//catch主异常的父类
try {
InputStream inputStream = new FileInputStream(new File(""));
}catch (Exception e){
//务必打印异常信息 项目中log.error 或者是 log.warn() 根据具体业务区分
e.printStackTrace(); //本地测试可用这个
log.error("Exception:", e);
}
}
// 假如说我要对外暴露一个接口或者是给页面提供的一个接口
//对于使用你接口的人,他肯定不希望看到一堆异常信息,对于网站的使用者更不希望看到 体验性很差
//所以我们会在最外层 catch主所有异常
public void method(){
try{
handleOne();
handleTwo();
handleThree();
}catch (Exception e){
}
}
public void handleOne() {
//逻辑处理
}
public void handleTwo() {
//逻辑处理
}
public void handleThree() {
//逻辑处理
}