今天来介绍了两个陌生又熟悉的异常类,熟悉是因为我们经常会遇到它们,陌生是好像又从来不知道它们是做什么的

假定读者已经清楚了Java的异常分类:

  1. 一是程序不能处理的错误(Error),
  2. 二是程序应该避免而可以不去捕获的运行时异常(RuntimeException),
  3. 三是必须捕获的非运行时异常,也叫受检异常或必检异常

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

总结

  1. InvocationTargetException是在使用反射中发生的异常,包裹了原始的异常
  2. 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异常介绍的更多相关文章

  1. [C#] C# 知识回顾 - 异常介绍

    异常介绍 我们平时在写程序时,无意中(或技术不够),而导致程序运行时出现意外(或异常),对于这个问题, C# 有专门的异常处理程序. 异常处理所涉及到的关键字有 try.catch 和 finally ...

  2. Java_异常介绍

    今日内容介绍: 掌握异常概述 理解异常的基础操作以及最简单的捕获处理 理解多异常捕获处理 理解声明抛出异常 掌握自定义异常 掌握异常处理注意事项 异常 什么是异常?Java代码在运行时期发生的问题就是 ...

  3. PendSV异常介绍、用于上下文切换

    在这里,非常感谢<cortex-cm3权威指南>的翻译者. PendSV 的典型使用场合是在上下文切换时(在不同任务之间切换). 例如, 一个系统中有两个就绪的任务,上下文切换被触发的场合 ...

  4. Java Exception异常介绍

     一:介绍java异常       异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通 过API中Throwab ...

  5. oracle 10g 学习之游标使用和异常介绍(11)

    一.游标 1. 使用游标 要求: 打印出 80 部门的所有的员工的工资: salary: xxx declare --1. 定义游标 cursor salary_cursor is select sa ...

  6. java中异常介绍

    一.异常概述 异常处理已经成为衡量一门语言是否成熟的标准之一,目前的主流编程语言如C++.C#.Ruby.Python等,大都提供了异常处理机制.增加了异常处理机制后的程序有更好的容错性,更加健壮. ...

  7. Java 异常介绍

    Java标准库内建了一些通用的异常,这些类以 Throwable 为顶层父类.Throwable又派生出 Error 类和 Exception 类. 错误:Error类以及他的子类的实例,代表了JVM ...

  8. 出现java.lang.reflect.UndeclaredThrowableException异常

    解决方案:1.看导进来的项目是否有中文路径.2.看是否有get.set方法没写.3.和部署的环境有关.比如,是否写了构造函数.EJB需要.

  9. 获取UndeclaredThrowableException异常信息

    一.堆栈错误信息如下,要获取红框里的message 说明:ValidationException为自定义异常,继承自Exception 二.代码如下

  10. Checked 和 UnChecked 异常 的使用场合

    异常的概念  任何的异常都是Throwable类(为何不是接口??),并且在它之下包含两个子类Error / Exception,而Error仅在当在Java虚拟机中发生动态连接失败或其它的定位失败的 ...

随机推荐

  1. gin 图片上传到本地或者oss

    路由层 func registerCommonRouter(v1 *gin.RouterGroup) { up := v1.Group("upload") { up.POST(&q ...

  2. Swift中的Optional类型

    Swift当中的Optional类型,表明一个变量可能有确认的值,也可能不包含任何值.不包含任何值在Swift当中,就是一个nil. Swift当中的变量或者常量,在使用之前必须得赋值,但是对于Opt ...

  3. windows server2012 挂载linux的nfs共享目录

    1.安装NFS客户端 首先win-server上添加角色-----选择文件服务-----网络文件系统(或者NFS客户端)-安装 2.挂载nfs目录 先cmd检查服务端的共享目录 然后执行:showmo ...

  4. 暴力破解(Pikachu)

    暴力破解(Pikachu靶场) Burpsuite4种攻击类型 Sinper(狙击手): 可以理解为一个一个爆破,也就是字典只能设置一个,然后用字典替换选择的参数,爆破完一个参数后再爆破另一个参数. ...

  5. Kafka架构以及一键化部署

    什么是Kafka? Apache Kafka是一个开放源代码的分布式事件流平台,成千上万的公司使用它来实现高性能数据管道,流分析,数据集成和关键任务等相关的应用程序. Kafka的应用场景 构造实时流 ...

  6. 怎么使用Stable diffusion中的models

    Stable diffusion中的models Stable diffusion model也可以叫做checkpoint model,是预先训练好的Stable diffusion权重,用于生成特 ...

  7. webpack js兼容处理

    webpack在不需要引入任何loader可以对于js进行打包处理,但是它不会对于js兼容性进行任务的处理,而我们编写的项目是需要在不同的浏览器中运行的,此时就需要对于js的兼容性在打包过程中进行对应 ...

  8. VIVO IQOO 5G 开关

    VIVO IQOO 5G 开关 在拨号盘输入*#*#2288#*#*,然后点击网络模式选择. -

  9. Kubernetes监控手册05-监控Kubelet

    上一篇我们介绍了如何监控Kube-Proxy,Kube-Proxy的/metrics接口没有认证,相对比较容易,这一篇我们介绍一下Kubelet,Kubelet的监控相比Kube-Proxy增加了认证 ...

  10. 30 岁的程序员,要有 "归零" 心态

    大家好,我是码农先森. 古话说的 "三十而立",正是担重之时,却大部分人在职场中都处于不上不下的尴尬境地.已经没有刚毕业时那股子冲劲,被生活和工作磨平了棱角. 在技术思想方面,似乎 ...