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

假定读者已经清楚了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. python的requests模块详解

    原文链接:https://www.cnblogs.com/lanyinhao/p/9634742.html 1.模块说明 requests是使用Apache2 licensed 许可证的HTTP库. ...

  2. 推荐一款模拟浏览器自动化操作神器!Mechanize

    大家好,我是狂师! 今天给大家推荐一款用于模拟浏览器行为以进行网页自动化操作Python库:Mechanize. 1.介绍 Mechanize是Python中的一个库,它被设计用来自动化网页浏览和数据 ...

  3. jQuery实现简单的模态框

    <!-- jquery模态框 --> <!DOCTYPE html> <html lang="en"> <head> <met ...

  4. go 通过指针修改结构体小写字段的值

    package main import ( "fmt" "unsafe" ) type W struct { b int32 c int64 } func ma ...

  5. 微服务新体验之Aspire初体验

    安装aspire 查看vs版本 我这的版本是17.9.7,不支持aspire,所以需要升级 更新VS 点击 帮助->检查更新 点击更新 静等安装升级 创建aspire项目 项目创建成功,如下图 ...

  6. centos7下利用qemu搭建arm模拟器

    1 目的 在centos7下使用qemu搭建arm模拟器. 参考博客: centos下利用qemu搭建arm模拟器 - 寒水司天 - 博客园 (cnblogs.com) 从零使用qemu模拟器搭建ar ...

  7. pandas基础--汇总和计算描述统计

    pandas含有是数据分析工作变得更快更简单的高级数据结构和操作工具,是基于numpy构建的. 本章节的代码引入pandas约定为:import pandas as pd,另外import numpy ...

  8. windows 开发者注册后写代码,这个给钱吗?

  9. 解决 Error running ‘Application‘: Command line is too long.

    一.项目场景:运行刚拉取下来的项目代码,出现下面问题描述的错误提示. 二.问题描述Error running 'Application': Command line is too long. Shor ...

  10. 每天打卡一小时 第三十一天 PTA520钻石 争霸赛

    第一题 源代码 #include<iostream> using namespace std; int main() { int n; cin>>n; cout<< ...