【Java异常】聊聊异常可能带来的坑

2023-12-23 23:27:33

一个活生生的案例

本周帮同事排查了一个问题,比较诡异的是他通过测试,并没有找到根本原因,只是发现有对应的错误日志。 但是其实并没有将堆栈信息打印出来。很难看出问题。添加了 e.printStackTrace();

get exception in exter: / by zero

显示出完整的错误信息。

java.lang.ArithmeticException: / by zero
	at com.exception.Test.f1(Test.java:24)
	at com.exception.Test.f2(Test.java:20)
	at com.exception.Test.main(Test.java:12)

    public static void main(String[] args) {
        try {
            Test t1 = new Test();
            t1.f2();
        } catch (Exception e) {
            System.out.println("get exception in exter: " + e.getMessage());
        }
    }

    public void f2() {
        f1();
    }

    public void f1() {
        System.out.println(10 / 0);
    }

异常实现原理

我们编写了一个Demo

    public static void main(String[] args) {
        try {
            System.out.println("try{}");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("finally");
        }
    }

执行之后,生成.class文件, 通过 javap -v 生产对应的字节码文件。

其中有一个异常表,from、to、target表示字节码的行号,当行号在[from,to]之间出现type异常,就会跳转到target行字节码继续执行。对应代码 也就是cacth的部分。而19到24就是catch-> finally的部分。

      Exception table:
         from    to  target type
             0     8    19   Class java/lang/Exception
             0     8    35   any
            19    24    35   any

在这里插入图片描述

异常性能分析

异常的整体步骤是 new创建异常对象、使用throw异常,打印异常调用链。
new 创建异常
如果我们的函数层级比较深的话,那么整个调用链是比较大。

public class Demo {
 public static void main(String[] args) {
   fe();
 }
 public static void fe() { fd(); }
 public static void fd() { fc(); }
 public static void fc() { fb(); }
 public static void fb() { fa(); }
 public static void fa() {
   RuntimeException e = new RuntimeException("oops!");
   
   // 打印strackTrace
   StackTraceElement[] stackTrace = e.getStackTrace();
   for (StackTraceElement element : stackTrace) {
     System.out.println(element);
   }
   
   throw e;
 }
}

在这里插入图片描述
异常抛出
当异常抛出的时候,之后能够catch的异常的栈可以解决,才不会向上抛异常,所以最好的方式及时处理抛出的异常,否则层级太深,对于性能以及问题排查都不好找。
在这里插入图片描述

最佳实践

在实际编码的时候,我们不仅仅需要在完成需求的同时,也需要考虑各种异常失败的情况,其实就是Deisgn for fail 。把失败处理当成一种错误处理也是一种业务逻辑,很多时候我们的逻辑代码都是在处理异常场景。比如检验参数、状态、数据异常、三方异常等等。所以在实际的编码中,我们需要考虑哪些地方可能会出现错误,那些地方不会。好的工程师的代码应对异常情况处理的更优雅。

文章来源:https://blog.csdn.net/jia970426/article/details/135171970
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。