【Java异常】Java异常监控重要手段 --异常链

news2025/1/10 16:34:12

目录标题

  • 前言
  • 一、异常链介绍
    • 1.1 异常链概述
    • 1.2 Java中如何使用异常链
  • 二、Throwable
    • 1.1 Throwable中哪些API提供存储cause的功能
    • 1.2 Throwable中如何获取cause
  • 三、项目实战演练
    • 示例1:未存储cause
    • 示例2:存储cause两层嵌套
    • 示例3:存储cause三层嵌套
  • 四、总结

前言

“异常链”无论是在框架源码中还是在日常项目开发中,都是一项非常重要的对异常处理的手段。

一、异常链介绍

1.1 异常链概述

以下摘抄自《Java编程思想》对异常链的介绍:

常常会想要在①捕获一个异常后抛出另一个异常②并且希望把原始异常的信息保存下来,这被称为异常链。

1.2 Java中如何使用异常链

在JDK1.4以前,程序员必须自己编写代码来保存原始异常的信息。现在所有Throwable的子类在构造器中都可以接受一个cause(因由)对象作为参数。这个cause就用来表示原始异常,这样通过把原始异常传递给新的异常,使得即使在当前位置创建并抛出了新的异常,也能通过这个异常链追踪到异常最初发生的位置。

扩展:
有趣的是,在Throwable的子类中,只有三种基本的异常类提供了带cause参数的构造器。它们是Error(用于Java虚拟机报告系统错误)、Exception以及
RuntimeException。如果要把其他类型的异常链接起来,应该使用initCause()方法而不是构造器。

二、Throwable

对于Throwable的继承体系,以及旗下Exception划分编译异常、运行异常的讲解此处略。 此处,主要是对Throwable中cause属性(存储原始异常)的讲解

1.1 Throwable中哪些API提供存储cause的功能

按照思路“*Throwable中的cause属性* 以及 *源码中肯定存在对cause属性的赋值操作*”,以“this.cause = cause”作为条件,我们直接来到Throwable的源码中进行查找,我们发现有四个API可以提供了存储cause的行为:

public class Throwable implements Serializable {
  
    private Throwable cause = this;
	
	// ①
	public Throwable(String message, Throwable cause) {
        fillInStackTrace();
        detailMessage = message;
        this.cause = cause;
    }
	
	// ②
	  public Throwable(Throwable cause) {
        fillInStackTrace();
        detailMessage = (cause==null ? null : cause.toString());
        this.cause = cause;
    }

	// ③
	protected Throwable(String message, Throwable cause,
                        boolean enableSuppression,
                        boolean writableStackTrace) {
        if (writableStackTrace) {
            fillInStackTrace();
        } else {
            stackTrace = null;
        }
        detailMessage = message;
        this.cause = cause;
        if (!enableSuppression)
            suppressedExceptions = null;
    }
     
    // ④
    public synchronized Throwable initCause(Throwable cause) {
        if (this.cause != this)
            throw new IllegalStateException("Can't overwrite cause with " +
                                            Objects.toString(cause, "a null"), this);
        if (cause == this)
            throw new IllegalArgumentException("Self-causation not permitted", this);
        this.cause = cause;
        return this;
    }
}

1.2 Throwable中如何获取cause

有存储肯定有获取,Throwable中提供获取cause的API是:



    /**
     * Returns the cause of this throwable or {@code null} if the
     * cause is nonexistent or unknown.  (The cause is the throwable that
     * caused this throwable to get thrown.)
     * 
     * @return  the cause of this throwable or {@code null} if the
     *          cause is nonexistent or unknown.
     * @since 1.4
     */
    public synchronized Throwable getCause() {
        return (cause==this ? null : cause);
    }

从注释“Returns the cause of this throwable or {@code null}”中,我们可以看到cause的值分为两种:

  1. this有值。即使用上述任意四种API存储了cause;
  2. null空值。即没有使用上述任意四种API。
    因此我们在使用getCause()方法的时候,需要注意空处理

三、项目实战演练

了解了cause相关的理论知识后,我们还必须通过代码的方式去验证我们的理论增强信服力加深印象

示例1:未存储cause

package com.atta.msgdactuator.zdemo;

import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;

/**
 * @author: cms
 * @date: 2023/1/7 9:03 PM
 * @description: xxx
 */
public class TestMain {

    public static void throwSQLIntegrityConstraintViolationException() throws SQLIntegrityConstraintViolationException {
        throw new SQLIntegrityConstraintViolationException("exception-SQLIntegrityConstraintViolationException");
    }

    public static void throwRuntimeException() {
        try {
            throwSQLIntegrityConstraintViolationException();
        } catch (SQLException e) {
            throw new RuntimeException();
        }
    }

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

在这里插入图片描述

示例2:存储cause两层嵌套

package com.atta.msgdactuator.zdemo;

import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;

/**
 * @author: cms
 * @date: 2023/1/7 9:03 PM
 * @description: xxx
 */
public class TestMain {

    public static void throwSQLIntegrityConstraintViolationException() throws SQLIntegrityConstraintViolationException {
        throw new SQLIntegrityConstraintViolationException("exception-SQLIntegrityConstraintViolationException");
    }

    public static void throwRuntimeException() {
        try {
            throwSQLIntegrityConstraintViolationException();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

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

在这里插入图片描述
通过调用e.getCause()获取到的是SQLIntegrityConstraintViolationException对象。

示例3:存储cause三层嵌套

package com.atta.msgdactuator.zdemo;

import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;

/**
 * @author: cms
 * @date: 2023/1/7 9:03 PM
 * @description: xxx
 */
public class TestMain {

    public static void throwSQLIntegrityConstraintViolationException() throws SQLIntegrityConstraintViolationException {
        throw new SQLIntegrityConstraintViolationException("exception-SQLIntegrityConstraintViolationException");
    }

    public static void throwSQLException() throws SQLException {
        try {
            throwSQLIntegrityConstraintViolationException();
        } catch (SQLIntegrityConstraintViolationException e) {
            throw new SQLException("exception-SQLException", e);
        }
    }

    public static void throwRuntimeException() {
        try {
            throwSQLException();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

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

在这里插入图片描述

四、总结

略。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/147871.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

构造题(agc059_b)

https://atcoder.jp/contests/agc059/tasks/ B - Arrange Your Balls Editorial / Time Limit: 2 sec / Memory Limit: 1024 MB Score : 700700 points Problem Statement You have NN balls of colors C_1, C_2, \ldots, C_NC1​,C2​,…,CN​. Here, all colors are rep…

引发C++程序内存错误的常见原因分析与总结

目录 1、概述 2、变量未初始化 2.1、变量未初始化的场景说明 2.2、对0xcccccccc、0xcdcdcdcd和0xfeeefeee等常见异常值的辨识度 3、空指针与野指针 3.1、空指针 3.2、野指针 4、线程栈溢出 5、内存越界 6、内存泄漏 7、堆内存被破坏 8、内存访问违例 8.1、访问64K…

7.Isaac教程--在Python中开发Codelets

在Python中开发Codelets 虽然就性能而言,编写小码的最佳语言是 C,但并非应用程序的所有小码都需要使用相同的语言。 Isaac SDK 还支持 Python codelets,或 pyCodelets,适合那些更熟悉 Python 的人。 本节向您展示如何执行以下操作…

可视化系列讲解:SVG绘制基本图形及如何复用

文章目录一、SVG坐标系二、SVG坐标系单位三、SVG绘制基本图形3.1 矩形3.2 圆形3.3 椭圆3.4 直线3.5 折线3.6 多边型3.7 路径3.8 文字3.9 图片四、SVG元素的组合五、图形元素定义复用和使用定义的复用5.1 defs与use5.2 symbol与use一、SVG坐标系 SVG 使用的坐标系统(…

【Python】函数——传递任意数量的实参

传递任意数量的实参和传递任意数量的关键字实参 *args:表示用来接收任意数量的实参,其中,形参*args的星号会让Python创建一个名为args的空元组,并将接收到的任意数量的实参存储在这个元组中。**kwargs:表示用来接收任…

ARX给CAD发送命令的几种方法

本文迁移自本人网易博客,写于2015年11月16日。1、ads_queueexpr( _T("(command\"_POINT\" \"1,1,0\")") );该函数CAD未公开,使用时提前声明下就可以了。可以参考帮助文件中:Tips and Techniques 。2、acDocMan…

嵌入式:人机交互接口设计详解

文章目录键盘和LED的接口原理HD7279A与S3C2410A的连接原理图键盘和LED控制的编程实例LCD显示原理LCD控制器概述嵌入式处理器与LCD的连接S3C2410A的LCD控制器(1)STN LCD(2)TFT LCDLCD控制器的框图LCD接口信号STN LCD控制器操作&…

Java IO流 - 转换流的使用详细介绍

文章目录转换流字符输入转换流字符输出转换流转换流 之前我们代码编码和文件编码都是UTF-8, 所以没有出现中文乱码的问题 我们知道代码编码和文件编码的格式如果不一致的话会出现中文乱码的问题 那么如果在开发中, 我们确实会遇到编码不一致的情况如何解决呢? 我们可以使用字符…

【高阶数据结构】手撕红黑树(超详细版本)

🌈欢迎来到数据结构专栏~~手撕红黑树 (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是Scort目前状态:大三非科班啃C中🌍博客主页:张小姐的猫~江湖背景快上车🚘,握好方向盘跟我有一起打天下嘞!送给自己的一句…

JMS规范和AMQP协议

参考资料:《JMS与AMQP简述以及比较》《AMQP协议详解》《MQ消息队列的JMS规范和AMQP协议的区别》《消息队列之JMS和AMQP对比》写在开头:本文为学习后的总结,可能有不到位的地方,错误的地方,欢迎各位指正。一般情况下MQ的…

【数据结构与算法——C语言版】6. 排序算法(3)——插入排序

前言 在本系列的上两篇文章分别介绍了两种O(n2)的排序算法——选择排序和冒泡排序,今天是第三种O(n2)的排序算法:插入排序。 插入排序 核心思想 它的基本思想是将一个记录插入到已经排好序的有序表中,从而产生一个新的、记录数增 1 的有序…

软件测试~自动化测试Seleniums---1

一.什么是自动化测试 1.自动化测试介绍 自动化测试指软件测试的自动化,在预设状态下运行应用程序或者系统,预设条件包括正常和异常,最后评估运行结果。将人为驱动的测试行为转化为机器执行的过程。 将测试人员双手解放,将部分测…

机器视觉(十):印刷体字符识别

目录: 机器视觉(一):概述 机器视觉(二):机器视觉硬件技术 机器视觉(三):摄像机标定技术 机器视觉(四):空域图像增强 …

Unreal模块创建流程

可以把开发中通用的功能封装成模块,以在不同项目之间复用,这里记录一下创建模块的步骤:在工程的Source文件夹中新建文件夹,命名为模块名称TestCustomModule:如果要区分模块内脚本的公私有权限,则在模块文件夹内创建Public和Private文件夹,这里我没有区分,就不创建了:在模块文件…

Js如何实现一个累加向上漂浮动画

前言 在不久之前,看到一个比较有意思的小程序,就是静神木鱼,可以实现在线敲木鱼,自动敲木鱼,手盘佛珠,静心颂钵的 整个小程序功能比较小巧,大道至简,曾风靡过一阵的,无论在App应用市场上,还是小程序里,一些开发者都赚得盆满钵满,用于缓解当代年轻人的一个焦虑,佛系解压,算是一…

Kubernetes:通过轻量化工具 kubespy 实时观察YAML资源变更

写在前面 分享一个小工具 kubespy 给小伙伴博文内容涉及: 工具的简单介绍下载安装以 kubectl 插件方式使用 Demo 理解不足小伙伴帮忙指正 我所渴求的,無非是將心中脫穎語出的本性付諸生活,為何竟如此艱難呢 ------赫尔曼黑塞《德米安》 简单介…

详解二分查找的两种写法以及二分查找的六种变形

目录 一、二分查找的两种写法 1.1 - 第一种写法(左闭右闭) 1.2 - 第二种写法(左闭右开) 二、二分查找的六种变形 2.1 - 查找第一个 target 的元素位置 2.2 - 查找第一个 > target 的元素位置 2.3 - 查找第一个 > ta…

JS类型转换机制

概述 JS中有六种简单数据类型:undefined、null、boolean、string、number、symbol,以及引用类型:object 但是我们在声明的时候只有一种数据类型,只有到运行期间才会确定当前类型let x y ? 1 : a; ,x的值在编译阶段…

FPGA基础之内置逻辑门

verilog语言中,针对逻辑门,有许多内置可直接使用的逻辑门,从输入输出数量可分为多输入门和多输出门。 一、多输入门 有单个或多个输入,只有单个输出的逻辑门,包含and(与),or(或),xor(异或)&am…

在训练心脏数据集时碰到的问题汇总

在训练心脏数据集时碰到的问题汇总: 1.nii数据处理问题 心脏CT数据集采用的是医学图像常用的压缩文件格式nii,且储存的图像为3D图像,不能直接使用。 首先应导入SimpleITK包,利用如下三个函数进行nii格式文件的提取。 sitk.ReadI…