调皮的 InvocationTargetException 异常

解决 InvocationTargetException 异常 【代码】解决 InvocationTargetException 异常。 阅读详情
AI摘要

博客讨论了在Java业务开发中,全局异常处理遇到的问题。当使用反射调用方法时,自定义的BusinessException被包装成InvocationTargetException,导致异常处理失效。文章解释了InvocationTargetException的作用,并提供了捕获自定义异常的方法,即在捕获到InvocationTargetException后,检查并重新抛出自定义异常。最后,文章探讨了如何优雅地处理这种情况。

在业务开发中,一般都会定义全局通用的业务异常,然后通过拦截器对全局异常进行解析,返回给调用端对应的信息, 但是在某些场景(比如反射)下,抛出的业务异常会被吞掉,导致调用端收到懵逼的,统一的错误信息。

1 背景

今天有同事反馈,自定义的数据校验(会抛出全局自定义的业务异常),通过反射执行后,抛出的自定义业务异常没有被捕获到,一脸 o((⊙﹏⊙))o,这里用示例代码模拟下:

BusinessException 自定义的业务异常类

public class BusinessException extends Exception {
    private static final long serialVersionUID = 1L;

    private String code;
    private String message;

    public BusinessException(String code, String message) {
        this.code = code;
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public String getCode() {
        return code;
    }
}

Form 验证表单

public class Form {

    public void validate() throws BusinessException {
        throw new BusinessException("10000", "缺少必要的参数");
    }
}

测试用例

public class TestCase {

    @Test
    public void error() throws BusinessException {
        try {
            Class<?> clazz = Class.forName("com.fairy.exercise.base.proxy.exec.Form");
            Method method = clazz.getMethod("validate");
            method.invoke(clazz.newInstance());
        } catch (ClassNotFoundException e) {
            System.out.println("异常:ClassNotFoundException 抛出");
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            System.out.println("异常:NoSuchMethodException 抛出");
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            System.out.println("异常:InvocationTargetException 抛出");
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            System.out.println("异常:IllegalAccessException 抛出");
            e.printStackTrace();
        } catch (InstantiationException e) {
            System.out.println("异常:InstantiationException 抛出");
            e.printStackTrace();
        }
    }
}

为了查看具体的异常,所以这里一个一个单独捕捉。

注意:如果直接 catch BusinessException 异常,不好意思,会直接报错,因为识别到的受控异常是 InvocationTargetException 异常。

运行结果如下:

通过输出发现,业务中抛出的业务异常,被包装成了 InvocationTargetException 异常,也就是说,被 InvocationTargetException 给吞了,原来结在这里。

2 查查 InvocationTargetException 背景

查看源码快速锁定:

package java.lang.reflect;

/**
 * InvocationTargetException is a checked exception that wraps
 * an exception thrown by an invoked method or constructor.
 *
 * <p>As of release 1.4, this exception has been retrofitted to conform to
 * the general purpose exception-chaining mechanism.  The "target exception"
 * that is provided at construction time and accessed via the
 * {@link #getTargetException()} method is now known as the <i>cause</i>,
 * and may be accessed via the {@link Throwable#getCause()} method,
 * as well as the aforementioned "legacy method."
 *
 * @see Method
 * @see Constructor
 */
public class InvocationTargetException extends ReflectiveOperationException {
    ...
}

通过源码可以看到,位置:java.lang.reflect,其是一个受控异常,包装触发目标方法或者构造函数抛出的异常。哦,原来目标方法和构造函数抛出的异常都会包装成 InvocationTargetException 异常。到这里也就解答了同事的疑问。

但是问题又来了,为什么要包装成 InvocationTargetException 异常呢。

下面这几段摘自:www.zhihu.com/question/56…

因为 原来的异常 无法直接以一种统一而又明确的方式表达出来,所以使用 InvocationTargetException来将原来的异常包装起来,通过多加一层间接层的方式来提供统一的访问途径。

Java 方法可以静态声明它可能会抛出一组固定的异常类型。而反射 API 里,Method.invoke() 与 Constructor.newInstance() 这些方法有 双重身份, 它们既代表要调用指定的目标方法,自身也是一个方法;目标方法可能会抛出异常,而它们自身在调用目标方法前也可能会抛出一些异常(例如IllegalArgumentException)。

它们要调用的目标方法可能抛出任意 Throwable 类的派生类的异常,但它们自身却不能根据要调用的目标而“动态”改变自己声明要抛出的异常类型,而只能静态声明一组可能抛出的异常类型。

声明抛出 Throwable 或 Exception 的话,这就太宽泛,难以准确反映异常的原因和意图;但不声明成这么宽泛的异常类型的话又无法完整覆盖所有可能由目标方法抛出的异常。

那怎么办?简单,新增一个 check exception 类型,InvocationTargetException,将原本由目标方法抛出的异常包装起来,这样就可以给 Method.invoke() / Constructor.newInstance() 的调用者一个统一的接口,既明确了 这个异常是由目标方法抛出的,不是由我自己抛出的 的意图,又能完整覆盖目标方法所能抛出的所有异常类型(InvocationTargetException.getTargetException() / getCause() 的类型是Throwable)


3 怎么才能捕获自定义的异常

其实就是在捕捉到 InvocationTargetException 异常后,对此异常进行处理,然后再抛出对应的业务异常。

修改后的测试用例如下

public class TestCase {

    @Test
    public void error() throws BusinessException {
        try {
            Class<?> clazz = Class.forName("com.fairy.exercise.base.proxy.exec.Form");
            Method method = clazz.getMethod("validate");
            method.invoke(clazz.newInstance());
        } catch (ClassNotFoundException e) {
            System.out.println("异常:ClassNotFoundException 抛出");
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            System.out.println("异常:NoSuchMethodException 抛出");
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // 🚀:重点关注代码块
            if (e.getTargetException() instanceof BusinessException) {
                System.out.println("异常:BusinessException 抛出");
                e.getCause().printStackTrace();
                // 抛出 BusinessException 类型的异常
                // throw (BusinessException) e.getTargetException();
            } else {
                System.out.println("异常:InvocationTargetException 抛出");
                e.printStackTrace();
            }
        } catch (IllegalAccessException e) {
            System.out.println("异常:IllegalAccessException 抛出");
            e.printStackTrace();
        } catch (InstantiationException e) {
            System.out.println("异常:InstantiationException 抛出");
            e.printStackTrace();
        }
    }
}

运行结果输出:

查看输出结果,是符合预期的,但是这种处理方式就是对症下药,不知道有没有更加温和的方式。

Java异常处理:InvocationTargetException 需要注意的是,在使用反射调用方法时,如果目标方法本身是私有的或者受保护的,我们需要使用setAccessible方法来设置可访问性。当我们通过反射调用一个方法时,如果目标方法本身抛出了异常,那么调用代码会捕获这个异常并将其封装在InvocationTargetException中。当使用Java的反射机制调用一个方法时,如果目标方法本身抛出了异常,那么反射调用的代码会捕获这个异常,并将其封装在InvocationTargetException中抛出。 阅读详情

相关推荐

LangChain + Milvus Lite:从零搭建本地RAG知识库

本文详细介绍了如何利用LangChain、Milvus Lite和gte-large-zh模型,在本地从零搭建一个完整的RAG知识库系统。文章涵盖了环境配置、文档处理与向量化、本地向量库构建以及检索问答实现的全流程,重点突出了完全本地化部署带来的数据隐私安全和成本优势,为开发者提供了一条实践性极强的技术路径。

weixin_29044713的博客 444

InvocationTargetException

解决:判断是否为空,为空则进行操作(如赋值)。原因:参数为null,转换类型异常。

khmff的博客 1万+

手把手教你用TP4056和PMOS管搭建锂电池自动切换电路(含元器件选型指南)

本文详细介绍了如何使用TP4056和PMOS管搭建锂电池自动切换电路,包括核心架构设计、元器件选型指南和PCB布局优化。通过智能充电算法和电源路径切换模块,实现外部供电与锂电池的无缝切换,提升便携式设备的电源管理效率。

julia4scientist的博客 889

python魔术方法学习

实例方法 1、在定义实例时,会初始化一个实例对象,其第一个参数一般为self,在创建时候将其传给self, 2、实例的方法和属性只能由实例调用 类方法 1、在类定义中,必须用@classmethod装饰器修饰的方法 2、必须至少有一个参数,第一个参数留给了cls,cls指待调用者即类本身 3、cls这个标识符可以是任意合法名称,但是为了易读性,一般写成cls 4、通过cls直接操作类的属性即方法 静态方法 1、在类定义中,必须用@staticmethod装饰器修饰的方法 2、在调用时不用隐形的传入参数,静态

qq_42971895的博客 453

内核工作FAST‘25 Artifact Evaluation流程记录

在我们的paper中,复现需要用到傲腾持久化内存,因此,需要AE Reviewer访问到内网服务器中。我们的思路是购买云服务器,将其作为跳板机,内网服务器通过SSH反向代理与公网服务器建立隧道,AE Reviewer通过隧道访问内网服务器。我们在AE过程中使用。然后,把一切复现需要的代码环境,在chroot里面配置完成。

不定期更新系统使用、编程小技巧,哔哩哔哩账号:https://space.bilibili.com/399455629,欢迎关注 1215

TP4056锂电池充电电路设计原理与工程实践

锂离子电池充电管理是嵌入式电源系统的核心基础技术,其本质是通过恒流恒压(CC/CV)控制策略,匹配电池电化学特性以实现安全、高效、长寿命充放电。TP4056作为典型线性充电IC,以精简外围实现预充、恒流、恒压及自动截止全周期管理,但受限于线性拓扑的热耗散特性,必须协同散热设计、电阻精度选型与PCB布局进行系统级优化。该方案广泛应用于STM32智能小车、便携传感器节点等3.7V单节锂电供电场景,兼顾成本、可靠性与工程可实施性,是入门嵌入式硬件电源设计的关键实践范例。

weixin_36064575的博客 219

已解决:java.lang.reflect.InvocationTargetException 异常的正确解决方法,亲测有效!!!

是一个包装异常,通常在使用反射调用方法时出现。通过正确处理中封装的实际异常,可以有效解决这一问题。本文提供了详细的解决方案和代码示例,帮助开发者理解并解决问题。希望本文对您有所帮助,如有其他问题,欢迎讨论!

猿鹏探码的博客 4万+

2026华为OD面试题029:勇攀数字高峰

在给定的数字地形图里寻找登山路径,数字代表当前位置的海拔高度。要求从最低海拔出发,不断攀登,最终到达最高山峰。地图保证最低海拔和最高山峰都只有一个。 登山规则: - 路径上的海拔必须严格递增 - 只能向上下左右 4 个方向移动 - 路径必须从最低海拔开始,到最高海拔结束 - 每个地点只能走一次 - 每一步的攀登高度差必须大于 0,且不超过指定值 `K` 输出满足条件的登山路径的数量。

琅嬛福地 116

InvocationTargetException异常处理

InvocationTargetException 是一种包装由调用方法或构造方法所抛出异常的受查异常。

znxncnfn的博客 2万+

把机器学习“搬进”数据库:SAP HANA PAL 快速上手与 ABAP AMDP 实战

摘要:本文探讨了SAP HANA PAL(Predictive Analysis Library)在企业数据分析中的实践应用。PAL通过将机器学习算法下推到数据库内部执行,有效解决了大数据量场景下的数据搬运瓶颈和治理成本问题。文章详细介绍了PAL的核心功能(包括聚类、分类、回归等10类算法)、使用前提(版本、组件和权限要求)以及通过AMDP实现ABAP与PAL集成的技术方案。重点阐述了参数表设计理念和两个典型应用场景:利用PageRank算法分析企业权限网络关系,以及通过PAL_SCALE进行特征预处理。文

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 5738

[VCS]VCS dump fsdb的精细化控制

本文介绍了VCS FSDB波形dump的精细化控制方法。主要内容包括:1)基本dump方式;2)通过$fsdbDumpoff排除特定层次;3)使用$fsdbDumpvars选择性dump指定模块;4)运行时动态控制dump开关;5)通过文件管理排除列表($fsdbDumpoffFile或自定义读取);6)层次控制策略(剪除整棵树或仅当前层)。这些方法可有效控制波形文件大小,提高仿真效率。

元直的博客 1033

关于java中的异常抛出InvocationTargetException的总结(javaweb学习遇到的坑)

InvocationTargetException异常原因一、问题描述二、问题分析三、异常产生原因1、InvocationTargetException异常2、附一个例子 一、问题描述 做黑马旅游网项目的时候在从数据库中获取分类条目(category)的时候抛出如下异常: 这个反射异常出现的位置是BaseServlet文件,刚开始不知道这个异常产生的原因一直以为是BaseServlet里面的问题,却忽略了其他的文件。由于项目中间搁置了一段时间后才继续跟着做导致前面的某些操作就忘了,重新看了一遍视频才发现问

梦中注定的博客 4万+

实战复盘:纷玩岛(Livelab)候补订单微信支付协议的逆向与复现

通过本次对纷玩岛候补支付接口的分析,我们实现了一个脱离 App UI 的轻量级支付发起器。这不仅验证了其API的设计逻辑(Standby -> PrePayInfo 分层设计),也为后续的自动化监控或辅助抢票工具提供了支付环节的技术验证。技术本无罪,关键在于如何使用。理解这些底层协议,有助于我们写出更健壮的代码,也能在遇到线上支付问题时快速定位是业务层(API)问题还是通道层(微信)问题。

猫敷雪 801

InvocationTargetException异常分析

java.lang.reflect.InvocationTargetException 报此异常,是该方法内try {}catch(){抛出异常e.printStackTrace()},或者调用远程服务器所导致的一样:例如: 总结以下导致原因; 1.远程代码ip加端口获取远程跨服拒绝连接和服务器未启动所导致的,是由调用方法或构造方法所抛出异常的受检查的异常. 2.有可能

jiaysoft的博客 15万+

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

新环境打包后运行报错java.lang.reflect.InvocationTargetException

jdk版本不对、定时任务没有使用组件调用任务却用了绝对路径

qq_41623592的博客 7570

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Java反射异常处理之InvocationTargetException

InvocationTargetException异常由Method.invoke(obj, args...)方法抛出

岁月静好 34万+

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

理解 Java 中的 java.lang.reflect.InvocationTargetException 错误

在本文中,我们了解了在 Java 中使用反射层时如何包装底层异常。我们了解了在使用时如何获取底层异常以及如何解决它。

迹忆客 1万+

InvocationTargetException异常

InvocationTargetException异常由Method.invoke(obj, args...)方法抛出。当被调用的方法的内部抛出了异常而没有被捕获时,将由此异常接收。 百度了一下,是这样说的: 一、InvocationTargetException 是一种包装由调用方法或构造方法所抛出异常的受查异常。这个异常并不是Eclipse插件开发特有的,而是标准JDK中的,它定义在 ja

Taylor_Joe的博客 1万+

Java异常之InvocationTargetException

背景 前段时间发现了一个小问题,这里分享一下,希望能够帮到有需要的小伙伴 过程 java.lang.reflect.Method#invoke,由于invoke方法里抛了异常我们调用的时候一般都会捕获一下。

sunshine的博客 6250

InvocationTargetException原因分析

前几天碰到这个异常,当时在代码里追踪这个错误原因的时候,还真有点不知所措,不过后来还是找到了,现在有点儿空,记一下。异常全称:java.lang.reflect.InvocationTargetException本来代码在线上运行得很正常,那天同事从线上copy了一份下来在本地运行,不知道为什么一进入那个页面就报这个错,实在找不出原因,后来交给我。      凭经验跟直觉,我很快定位了

luoduyu的专栏 16万+

Java异常处理之InvocationTargetException(反射异常)

InvocationTargetException来将原来的异常包装起来,通过多加一层间接层的方式来提供统一的访问途径。Java方法可以静态声明它可能会抛出一组固定的异常类型。而反射API里,Method.invoke() 与 Constructor.newInstance() 这些方法有“双重身份”——它们既代表要调用指定的目标方法,自身也是一个方法;目标方法可能会抛出异常,而它们自身在调用目标...

liuyinfei_java的博客 1万+

关于 InvocationTargetException (调用目标异常)的解决

问题截图解决方法。

小象的个人博客 1023

java.lang.reflect.InvocationTargetException

产生原因: 1、包冲突、有重复包或者缺少包 2、项目jdk和部署jdk版本不一样,导致InvocationTargetException异常信息返回一个空值,没有调用invoc里的重写消息方法。 3、映射文件发生改变 对于不同原因的解决: 1、包:直接自己挨着查看就是了,但是一定要注意遇到重复包的时候你的系统究竟需要哪一个版本 2、jdk版本: ⑴、更换jdk包 ⑵、用一个方法统一处理该异常 pr...

This is oH2Oo 13万+
上一篇: 金九银十,啃透SpringBoot笔记文档,面试不再发愁
下一篇: java类和对象——如何面向对象以及类的定义、使用和实例化
Java技术那些事儿
博客等级 码龄5年 2306粉丝 2584原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值