Java Language——异常处理

Throwable 是整个 Java 异常体系的顶层父类,它有两个子类,分别是 Error 和 Exception,Error 是程序无法处理的系统错误(系统崩溃、JVM 错误),编译器不做检查;Exception 是程序可以处理的异常,捕获后可能恢复。

Exception 又分为 RuntimeException 和非 RuntimeException(也称为 Checked Exception),RuntimeException 是不可预知的,程序应当自行避免;非 RuntimeException 是可预知的,是从编译器校验的异常。

从责任角度看,Error 属于 JVM 需要负担的责任,RuntimeException 属于程序应该负担的责任,非 RuntimeException 是 Java 编译器应该负担的责任。

Java 异常体系 思维导图

Java 异常处理主要依赖于 try、catch、finally、throw、throws 五个关键字。

1、异常处理语法结构

try {
	int i = 10 / 0; // 会抛出异常
	// 自行抛出异常,throw 抛出的是一个异常实例,每次只能抛出一个
	// throw 抛出 Checked Exception: throw 语句要放在 try 块里或者一个带 throws 声明抛出的方法中
	// throw 抛出 RuntimeException: 自由放
	// throw new RuntimeException("");
} catch(ArithmeticException e) { // 捕获异常
	// 捕获 ArithmeticException
	log.error("类名.方法名 error", e); // 抛出的异常打印在日志中
} catch(Exception e) { 
	// 捕获 Exception
	log.error("类名.方法名 error", e);
	// throw new RuntimeException(""); // 再次抛出异常
	// System.exit(1); // 退出虚拟机, finally块失去执行的机会
} finally { // 资源回收块
}
  • try 块是必需的,catch 块和 finally 块至少出现其中一个;
  • catch 块按顺序进行捕获,如果被捕获了,则后面的 catch 块不会被执行,如果找不到可以捕获的 catch 块,则继续向上抛出异常,如果到了最外层都无法捕获,则 Java 运行时环境终止,程序在此退出;
  • 如果 finally 中有 return 语句,则 try、catch 中的 return 失效,总是执行 finally 中有 return;
  • finally 中的语句(如果有 return,则表示 return 前的语句)会在 try、catch 中的 return 之前执行。

看下执行顺序的范例:

try {
	logger.info("hello"); // 第一步
	return true;
} catch(Exception e) {
} finally {
	logger.info("world"); // 第二步
	return false; // 第三步
}
try {
	logger.info("hello"); // 第一步
	return true; // 第三步
} catch(Exception e) {
} finally {
	logger.info("world"); // 第二步
}
try {
	int i = 10 / 0; // 第一步
	return true; 
} catch(Exception e) {
	logger.error("类名.方法名 error", e); // 第二步
	return false; // 第四步
} finally {
	logger.info("world"); // 第三步
}

2、使用 throws 声明抛出异常:

当前方法不知如何处理出现的异常,抛由上一级调用者处理;main 方法抛出的异常则交由 JVM 处理(打印异常的跟踪栈信息并中止程序运行)。

// 此处异常将交由JVM处理
public static void main(String[] args) throws IOException{
}

注意:子类方法抛出的异常范围应小于等于父类,父类异常的 catch 块都应该排在子类异常 catch 块的后面。

3、自定义业务异常类:

在用户看来,应用系统发生的所有异常都是应用系统内部的异常。所以需要设计一个通用的继承自 RuntimeException 的异常来统一处理:

public class BizException extends RuntimeException {
	private static final long serialVersionUID = 1L;
	public BizException() {
        super();
    }
    public BizException(String message) {
        super(message);
    }
    public BizException(String message, Throwable cause) {
        super(message, cause);
    }
    public BizException(Throwable cause) {
        super(cause);
    }
}

其余异常都统一转译为上述异常 BizException,在 cache 之后,抛出上述异常的子类,并提供足以定位问题的信息,由控制器层接收 BizException 做统一处理。

4、异常链

分层结构:表现层(用户界面)–>中间层(业务逻辑)–>持久层(保存数据)
上层功能的实现严格依赖于下层的API,不会跨层访问
异常转译:捕获异常后抛出一个新的业务异常(包含对用户的提示信息)
这种把捕获的一个异常接着抛给另一个异常,并把原始异常信息保存下来是一种典型的链式处理(23种设计模式之一:职责链模式),也被称为“异常链”。

5、异常跟踪栈

当产生异常的时候,异常从方法1触发,传到方法2,再传到方法3…最后传到main方法,在main方法终止,这个过程就是Java的异常跟踪栈。
方法调用栈:面向对象的应用运行时,会发生一系列方法调用,从而形成“方法调用栈”。

6、JDK1.7 增强的功能

多异常捕获:

try {
} catch(IndexOutOfBoundsException|NumberFormatException|NullPointerException e) {
}

增强了try 块:

允许在 try 关键字后加 ( ) ,圆括号可声明、初始化一个或多个资源,具体指那些必须在程序结束时显式关闭的资源,比如数据库连接、网络连接、流等,这些资源实现类必须实现 AutoCloseable 或 Closeable,实现 close() 方法,try 语句在该语句结束的时候自动关闭这些资源。
自动关闭资源的 try 语句相当于包含了隐式的 finally 块(用于关闭资源),故这个 try 语句可以既没有 catch 块,也没有 finally 块。

try (
        // 声明、初始化可关闭资源, try语句会自动关闭
        BufferedReader br = new BufferedReader(new FileReader("Test.java"));
) {
    // 使用资源
    System.out.println(br.readLine());
} catch (Exception e) {
} finally {
}

7、Java 异常处理使用建议

  • 不要过度使用异常;
  • try 块避免庞大;
  • 避免 finally 块中使用 return 或 throw 等导致方法终止的语句;
  • 避免使用 CatchAll 语句。

CatchAll 语句:

try (
} catch(Throwable t) {
}

8、try-catch 存在性能问题?

  • 通过对比编译后的字节码,可以发现 try-catch 块会影响 JVM 指令重排序的优化;
  • 遇到异常后,便会实例化一个 Exception,并且会对 Exception 对象实例保存栈快照等信息,开销较大。

所以说在不发生异常的情况下,try-catch 块对性能的影响非常小,遇到异常后开销较大。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值