InvocationTargetException和UndeclaredThrowableException异常介绍
今天来介绍了两个陌生又熟悉的异常类,熟悉是因为我们经常会遇到它们,陌生是好像又从来不知道它们是做什么的
假定读者已经清楚了Java的异常分类:
- 一是程序不能处理的错误(Error),
- 二是程序应该避免而可以不去捕获的运行时异常(RuntimeException),
- 三是必须捕获的非运行时异常,也叫受检异常或必检异常
InvocationTargetException
反射操作过程中,调用目标类的方法可能抛出异常,可以使用Throwable接受,但是太宽泛了
InvocationTargetException就是为解决这个问题而设计的,当反射操作的目标方法中出现异常时,都统一包装成一个必检异常 InvocationTargetException
InvocationTargetException的target属性保存了原始的异常
package exception;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ExceptionTest{
public static void makeInvocationTargetException() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException{
Class<ExceptionTest> exceptionTestClass = ExceptionTest.class;
Method throwExceptionMethod = exceptionTestClass.getMethod( "throwExceptionMethod" );
throwExceptionMethod.invoke( new ExceptionTest() );
}
public void throwExceptionMethod(){
int i = 1 / 0;
}
public static void main( String[] args ) throws Exception{
makeInvocationTargetException();
}
}
输出以下异常,可以看出首先是打印的是InvocationTargetException,后续接着打印了真正异常发生的位置
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at exception.ExceptionTest.makeInvocationTargetException(ExceptionTest.java:12)
at exception.ExceptionTest.main(ExceptionTest.java:22)
Caused by: java.lang.ArithmeticException: / by zero
at exception.ExceptionTest.throwExceptionMethod(ExceptionTest.java:17)
... 6 more
UndeclaredThrowableException
如果子类中要重写父类中的方法,那么子类方法中抛出的必检异常必须是父类方法中声明过的类型。
代理类一般有两种实现方式:实现目标类相同的接口或者继续目标类
- 如果代理类和被代理类实现了共同的接口,那代理类方法抛出的受检异常必须是共同接口中声明过的
- 如果代理类是被代理类的子类,则代理类方法报错的受检异常必须是被代理类的方法中声明过的
可以代理类难免会抛出一些接口或者父类没有声明的受检异常,这时候不抛出,它是受检异常,必须抛出;抛出,没有声明
所以可以把这些受检异常包装为免检异常UndeclaredThrowableException抛出
package exception;
import java.io.IOException;
public interface IPerson{
void sayHello() throws IOException;
}
package exception;
public class Person implements IPerson{
@Override
public void sayHello(){
System.out.println( "Hello" );
}
}
package exception;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
public class PersonRecord implements InvocationHandler{
Object object;
public PersonRecord( Object object ){
this.object = object;
}
@Override
public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable{
System.out.println( "record start" );
Object rs = method.invoke( object, args );
System.out.println( "record end" );
throw new Exception();
}
}
package exception;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class UndeclaredExceptionTest{
public static void makeUndeclaredThrowableException() throws IOException{
IPerson o = (IPerson)Proxy.newProxyInstance( UndeclaredExceptionTest.class.getClassLoader(), new Class[]{ IPerson.class },
new PersonRecord(new Person()) );
o.sayHello();
}
public static void main( String[] args ) throws Exception{
makeUndeclaredThrowableException();
}
}
会有以下输出
record start
Hello
record end
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
at com.sun.proxy.$Proxy0.sayHello(Unknown Source)
at exception.UndeclaredExceptionTest.makeUndeclaredThrowableException(UndeclaredExceptionTest.java:14)
at exception.UndeclaredExceptionTest.main(UndeclaredExceptionTest.java:21)
Caused by: java.lang.Exception
at exception.PersonRecord.invoke(PersonRecord.java:25)
... 3 more
同时发生
这两个异常可以同时发现,也就是在代理类中使用了反射操作,然后异常被包装为InvocationTargetException,而InvocationTargetException没有被接口或者父类声明过,于是又被保证为UndeclaredThrowableException
我们将Person的sayHello方法改一下:
package exception;
public class Person implements IPerson{
@Override
public void sayHello(){
System.out.println( "Hello" );
int i = 1/0;
}
}
这样就会同时触发这两种异常
record start
Hello
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
at com.sun.proxy.$Proxy0.sayHello(Unknown Source)
at exception.UndeclaredExceptionTest.makeUndeclaredThrowableException(UndeclaredExceptionTest.java:14)
at exception.UndeclaredExceptionTest.main(UndeclaredExceptionTest.java:21)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at exception.PersonRecord.invoke(PersonRecord.java:23)
... 3 more
Caused by: java.lang.ArithmeticException: / by zero
at exception.Person.sayHello(Person.java:9)
... 8 more
总结
- InvocationTargetException是在使用反射中发生的异常,包裹了原始的异常
- UndeclaredThrowableException是在代理中发生的异常,包裹了原始的异常
在工作的过程中,会经常的遇到这两个异常,以前只是选择性的把它忽略了,在我们了解了他们的组成和原理之后可以更好的找到原始异常
下面是一个Mybatis的工具类,目的是从包装异常类中找到原始的异常:
/**
* Copyright 2009-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ibatis.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
/**
* @author Clinton Begin
*/
public class ExceptionUtil {
private ExceptionUtil() {
// Prevent Instantiation
}
/**
* 拆解InvocationTargetException和UndeclaredThrowableException异常的包装,从而得到被包装的真正异常
* @param wrapped 包装后的异常
* @return 拆解出的被包装异常
*/
public static Throwable unwrapThrowable(Throwable wrapped) {
// 该变量用以存放拆包得到的异常
Throwable unwrapped = wrapped;
while (true) {
if (unwrapped instanceof InvocationTargetException) {
// 拆包获得内部异常
unwrapped = ((InvocationTargetException) unwrapped).getTargetException();
} else if (unwrapped instanceof UndeclaredThrowableException) {
// 拆包获得内部异常
unwrapped = ((UndeclaredThrowableException) unwrapped).getUndeclaredThrowable();
} else {
// 该异常无需拆包
return unwrapped;
}
}
}
}
InvocationTargetException和UndeclaredThrowableException异常介绍的更多相关文章
- [C#] C# 知识回顾 - 异常介绍
异常介绍 我们平时在写程序时,无意中(或技术不够),而导致程序运行时出现意外(或异常),对于这个问题, C# 有专门的异常处理程序. 异常处理所涉及到的关键字有 try.catch 和 finally ...
- Java_异常介绍
今日内容介绍: 掌握异常概述 理解异常的基础操作以及最简单的捕获处理 理解多异常捕获处理 理解声明抛出异常 掌握自定义异常 掌握异常处理注意事项 异常 什么是异常?Java代码在运行时期发生的问题就是 ...
- PendSV异常介绍、用于上下文切换
在这里,非常感谢<cortex-cm3权威指南>的翻译者. PendSV 的典型使用场合是在上下文切换时(在不同任务之间切换). 例如, 一个系统中有两个就绪的任务,上下文切换被触发的场合 ...
- Java Exception异常介绍
一:介绍java异常 异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通 过API中Throwab ...
- oracle 10g 学习之游标使用和异常介绍(11)
一.游标 1. 使用游标 要求: 打印出 80 部门的所有的员工的工资: salary: xxx declare --1. 定义游标 cursor salary_cursor is select sa ...
- java中异常介绍
一.异常概述 异常处理已经成为衡量一门语言是否成熟的标准之一,目前的主流编程语言如C++.C#.Ruby.Python等,大都提供了异常处理机制.增加了异常处理机制后的程序有更好的容错性,更加健壮. ...
- Java 异常介绍
Java标准库内建了一些通用的异常,这些类以 Throwable 为顶层父类.Throwable又派生出 Error 类和 Exception 类. 错误:Error类以及他的子类的实例,代表了JVM ...
- 出现java.lang.reflect.UndeclaredThrowableException异常
解决方案:1.看导进来的项目是否有中文路径.2.看是否有get.set方法没写.3.和部署的环境有关.比如,是否写了构造函数.EJB需要.
- 获取UndeclaredThrowableException异常信息
一.堆栈错误信息如下,要获取红框里的message 说明:ValidationException为自定义异常,继承自Exception 二.代码如下
- Checked 和 UnChecked 异常 的使用场合
异常的概念 任何的异常都是Throwable类(为何不是接口??),并且在它之下包含两个子类Error / Exception,而Error仅在当在Java虚拟机中发生动态连接失败或其它的定位失败的 ...
随机推荐
- WEB服务与NGINX(26)- 实现Nginx高并发系统内核参数优化
1. 实现Nginx高并发系统内核参数优化 由于默认的Linux内核参数考虑的是最通用场景,这明显不符合用于支持高并发访问的Web服务器的定义,所以需要修改Linux内核参数,使得Nginx可以拥有更 ...
- 🔥httpsok-v1.11.0支持CDN证书自动部署
httpsok-v1.11.0支持CDN证书自动部署 介绍 httpsok 是一个便捷的 HTTPS 证书自动续签工具,专为 Nginx .OpenResty 服务器设计.已服务众多中小企业,稳定.安 ...
- URP(Universal Render Pipeline)渲染管线在使用中的一些分享
本篇文章整理了URP管线使用中的一些简单的心得记述 1.使用ScriptableRendererFeature自定义渲染特性 在内建(Build-in)管线中可以使用CommandBuffer并添加到 ...
- C数据结构:二叉树的基本操作
二叉树 树基本知识 二叉树的性质 满二叉树 完全二叉树 性质4.5的解释 顺序存储结构(利用性质4.5) 链式存储结构 结点结构体 建立二叉树 先序遍历 中序遍历 后序遍历 层次遍历 复制二叉树 计算 ...
- C语言:输入一串字符串,统计字符串中有多少个数字
gets函数会在输入完字符后自动补上一个\0,所以用这个特性可以计算出字符串是否结束. 因为数字在字符中对应的ascii码就是0~9,只要遇到小于9的字符就是数字,所以计数器加一 #include&l ...
- docker 修改运行容器环境变量,如何修改容器中的环境变量env使长期有效
@ 目录 前言 第一步:查看Docker Root目录 第二步:查到容器的长id(container id) 第三步:停止容器 第四步:编辑修改环境变量env 第五步:重载服务的配置文件 第六步:重启 ...
- 【wordpress开发必备】新增必填字段相关函数和钩子,适用6.1版本
当表单包含多个必填字段时,它们的标签可能带有一个带有图例的星号,以说明这些字段是必填的.为了减少代码重复并帮助维护全局一致的标记,WordPress 有两个新函数:wp_required_field_ ...
- Android 13 - Media框架(28)- MediaCodec(三)
关注公众号免费阅读全文,进入音视频开发技术分享群! 上一节我们了解到 ACodec 执行完 start 流程后,会把所有的 input buffer 都提交给 MediaCodec 层,MediaCo ...
- 一个 .NET 开源的地图组件库 - Mapsui
前言 今天大姚给大家分享一个.NET开源(MIT License).免费.同时支持多平台框架(MAUI.WPF.Avalonia.Uno.Blazor.WinUI.Eto..NET Android 和 ...
- MyBatis完成CRUD 详细细节内容
1. MyBatis完成CRUD 详细细节内容 @ 目录 1. MyBatis完成CRUD 详细细节内容 每博一文案 2. MyBatis工具类SqlSessionUtil的封装 3. 准备工作 3. ...