分享一个你不知道的Java异常实现的缺陷

 更新时间:2022年12月07日 11:29:53   作者:程序员济癫  
Java中一个大家熟知的知识点就是异常捕获,try...catch...finally组合,但是很多人不知道这里面有一个关于Java的缺陷,或者说是异常实现的一点不足之处。本文就通过一个很简单的实验给大家演示下效果玩玩儿,希望大家能觉得有趣

前言

Java中一个大家熟知的知识点就是异常捕获,try...catch...finally组合,但是很多人不知道这里面有一个关于Java的缺陷,或者说是异常实现的一点不足之处。

我这边就通过一个很简单的实验给大家演示下效果玩玩儿,希望大家能觉得有趣。

模拟

1、自定义异常

这里,我们首先写一个自定义业务异常,专门用来抛出。

/**
 * <p>
 * 自定义业务异常
 * </p>
 *
 * @author 程序员济癫,公众号:【Java分享客栈】
 * @since 2022/12/6 19:20
 */
public class BusinessException extends RuntimeException {
   public BusinessException() {
      super();
   }

   public BusinessException(String errMsg) {
      super(errMsg);
   }

   public BusinessException(String errMsg, Throwable throwable) {
      super(errMsg, throwable);
   }

}

2、模拟异常

然后,我们写个测试方法来捕获并抛出空指针异常。

/**
 * <p>
 * 测试异常缺陷
 * </p>
 *
 * @author 程序员济癫,公众号:【Java分享客栈】
 * @since 2022/12/6 19:22
 */
@Slf4j
public class ExceptionTest {
   public static void main(String[] args) {
      try {
         UserInfo userInfo = null;
         System.err.println(userInfo.getName());
      } catch (Exception ex) {
         throw new BusinessException("捕获try的异常: " + ex.getMessage());
      }
   }
}

看下效果,OK没问题。

接下来,我们加上finally看看。

/**
 * <p>
 * 测试异常缺陷
 * </p>
 *
 * @author 程序员济癫,公众号:【Java分享客栈】
 * @since 2022/12/6 19:22
 */
@Slf4j
public class ExceptionTest {
   public static void main(String[] args) {
      try {
         UserInfo userInfo = null;
         System.err.println(userInfo.getName());
      } catch (Exception ex) {
         throw new BusinessException("捕获try的异常: " + ex.getMessage());
      } finally {
         System.err.println("----------finally最终执行---------");
      }
   }
}

看下效果,OK也没问题。

接下来我们这么做,在finally中抛出一个异常。

/**
 * <p>
 * 测试异常缺陷
 * </p>
 *
 * @author 程序员济癫,公众号:【Java分享客栈】
 * @since 2022/12/6 19:22
 */
@Slf4j
public class ExceptionTest {
   public static void main(String[] args) {
      try {
         UserInfo userInfo = null;
         System.err.println(userInfo.getName());
      } catch (Exception ex) {
         throw new BusinessException("捕获try的异常: " + ex.getMessage());
      } finally {
         System.err.println("----------finally最终执行---------");
         throw new BusinessException("覆盖catch的异常");
      }
   }
}

看下效果,发现catch的异常竟然被覆盖了。

虽然这种场景很特殊,但这其实就是Java在异常实现上美中不足的地方,因为异常是作为程序出错的标志绝对不应忽略,可是这种场景下异常的的确确丢失了。

接下来,我们再测试一种情况,在finally中使用return,看看会发生什么。

/**
 * <p>
 * 测试异常缺陷
 * </p>
 *
 * @author 程序员济癫,公众号:【Java分享客栈】
 * @since 2022/12/6 19:22
 */
@Slf4j
public class ExceptionTest {
   public static void main(String[] args) {
      try {
         UserInfo userInfo = null;
         System.err.println(userInfo.getName());
      } catch (Exception ex) {
         throw new BusinessException("捕获try的异常: " + ex.getMessage());
      } finally {
         System.err.println("----------finally最终执行---------");
         return;
      }
   }
}

看看效果,发现catch中捕获的异常干脆直接没了,仿佛从没来过。

最后,我们再演示一种你可能工作中干过或者见过的莫名其妙的事情。

我们修改一下这个测试方法,看代码。

/**
 * <p>
 * 测试异常缺陷
 * </p>
 *
 * @author 程序员济癫,公众号:【Java分享客栈】
 * @since 2022/12/6 19:22
 */
@Slf4j
public class ExceptionTest {
   public static void main(String[] args) {
      try {
         // 调用其他类的查询方法
         queryData();
      } catch (Exception ex) {
         // 捕获这个查询方法抛出的异常
         throw new BusinessException(ex.getMessage());
      }
   }

   private static void queryData() {
      try {
         // 这个方法刚好你也try..catch了,并且在finally中做了一些末尾必须执行的业务逻辑处理。
         UserInfo userInfo = null;
         System.err.println(userInfo.getName());
      } finally {
         doSomething();
      }
   }

   private static void doSomething() {
      // 业务处理过程中你同样习惯性地抛出了某个业务异常
      System.err.println("--------处理末尾业务--------");
      throw new BusinessException("处理末尾业务抛出逻辑异常");
   }
}

简单描述一下,你调用其他类的一个查询方法,那个方法可能习惯性的try..catch..finally了,而finally中还做了一些末尾必须要执行的操作,这个业务逻辑处理可能有几十行,你很可能又习惯性的做了一些判断以及异常的抛出。

别不相信,当一个项目进入中期甚至赶进度的时候,方法套方法,不少人已经在机械的茫然的写代码,也可能是在别人的基础上改代码,你很可能不会太仔细地一行一行去看那些代码里究竟有什么,恰巧测试的时候也没出什么大问题。

那么结果可能就是下面这样,你会发现自己一开始特意抛出的那个捕获该查询方法异常的玩意儿没一点效果,也不知道去哪儿了,怎么找也找不到,不知从哪儿冒出来下面这个莫名其妙的异常,后来想不到也就算了。

原因

这其实就是Java异常实现的一个不足,异常是程序出错的标志,怎么都不应该被忽略掉,更不用说是finally这种常用的行为,直接或间接地造成了异常的丢失。

《Thinking In Java》的作者有明确指出这个异常,认为这是相当严重的缺陷,是一个可能造成异常完全丢失的缺陷,而且是以一种更微妙、更难以察觉的方式在进行。

而C++就处理的很好,会将这种在第一个异常被处理之前抛出第二个异常的情况视为严重的编程错误。

总结

知道了这个缺陷后,其实就很好避免了。

1、避免在finally中抛出异常;

2、避免在finally中使用return;

3、catch中一定要养成log.error记录异常日志的好习惯,因为log是一定会记录下来的,至少不会让你毫无线索。

结尾再演示下加了日志的效果,只要是catch我都加上日志,那么一定不会错过。

到此这篇关于分享一个你不知道的Java异常实现的缺陷的文章就介绍到这了,更多相关Java异常实现缺陷内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 基于java的opencv开发过程详解

    基于java的opencv开发过程详解

    这篇文章主要介绍了基于java的opencv开发过程详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • spring data jpa 创建方法名进行简单查询方式

    spring data jpa 创建方法名进行简单查询方式

    这篇文章主要介绍了spring data jpa 创建方法名进行简单查询方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • Spring Boot与Spring MVC Spring对比及核心概念

    Spring Boot与Spring MVC Spring对比及核心概念

    这篇文章主要为大家介绍了Spring Boot与Spring MVC Spring的对比以及你需要了解的核心概念,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2022-03-03
  • Spring中的SpringApplicationRunListener详细解析

    Spring中的SpringApplicationRunListener详细解析

    这篇文章主要介绍了Spring中的SpringApplicationRunListener详细解析,SpringApplicationRunListener是一个监听SpringApplication中run方法的接口,在项目启动过程的各个阶段进行事件的发布,需要的朋友可以参考下
    2023-11-11
  • Java多线程之锁的强化学习

    Java多线程之锁的强化学习

    Java多线程的锁都是基于对象的,Java中的每一个对象都可以作为一个锁。这篇文章主要来通过一下示例为大家强化一下锁的相关知识的掌握,希望对大家有所帮助
    2023-02-02
  • Java Servlet简单实例分享(文件上传下载demo)

    Java Servlet简单实例分享(文件上传下载demo)

    下面小编就为大家带来一篇Java Servlet简单实例分享(文件上传下载demo)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • Java动态代理的示例详解

    Java动态代理的示例详解

    动态代理指的是,代理类和目标类的关系在程序运行的时候确定的,客户通过代理类来调用目标对象的方法,是在程序运行时根据需要动态的创建目标类的代理对象。本文将通过案例详细讲解一下动态代理,需要的可以参考一下
    2022-02-02
  • Java原生方法实现 AES 算法示例

    Java原生方法实现 AES 算法示例

    这篇文章主要介绍了Java原生方法实现 AES 算法,结合实例形式分析了Java实现AES加密算法的相关操作技巧,需要的朋友可以参考下
    2019-03-03
  • synchronized及JUC显式locks 使用原理解析

    synchronized及JUC显式locks 使用原理解析

    这篇文章主要为大家介绍了synchronized及JUC显式locks 使用原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Java如何简单快速入门JWT(token生成与验证)

    Java如何简单快速入门JWT(token生成与验证)

    这篇文章主要给大家介绍了关于Java如何简单快速入门JWT(token生成与验证)的相关资料,JWT是一个加密的字符串,JWT传输的信息经过了数字签名,因此传输的信息可以被验证和信任,需要的朋友可以参考下
    2023-12-12

最新评论