异常处理类-Throwable源码详解
package java.lang;
import java.io.*;
/**
*
* Throwable是所有Error和Exceptiong的父类
* 注意它有四个构造函数:
* Throwable()
* Throwable(String message)
* Throwable(Throwable cause)
* Throwable(String message, Throwable cause)
*
*/
public class Throwable implements Serializable {
private static final long serialVersionUID = -3042686055658047285L;
/**
* Native code saves some indication of the stack backtrace in this slot.
*/
private transient Object backtrace;
/**
* 描述此异常的信息
*/
private String detailMessage;
/**
* 表示当前异常由那个Throwable引起
* 如果为null表示此异常不是由其他Throwable引起的
* 如果此对象与自己相同,表明此异常的起因对象还没有被初始化
*/
private Throwable cause = this;
/**
* 描述异常轨迹的数组
*/
private StackTraceElement[] stackTrace;
/**
* 构造函数,起因对象没有被初始化可以在以后使用initCause进行初始化
* fillInStackTrace可以用来初始化它的异常轨迹的数组
*/
public Throwable() {
fillInStackTrace();
}
/**
* 构造函数
*/
public Throwable(String message) {
//填充异常轨迹数组
fillInStackTrace();
//初始化异常描述信息
detailMessage = message;
}
/**
* 构造函数,cause表示起因对象
*/
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;
}
/**
* 获取详细信息
*/
public String getMessage() {
return detailMessage;
}
/**
* 获取详细信息
*/
public String getLocalizedMessage() {
return getMessage();
}
/**
* 获取起因对象
*/
public Throwable getCause() {
return (cause==this ? null : cause);
}
/**
* 初始化起因对象,这个方法只能在未被初始化的情况下调用一次
*/
public synchronized Throwable initCause(Throwable cause) {
//如果不是未初始化状态则抛出异常
if (this.cause != this)
throw new IllegalStateException("Can't overwrite cause");
//要设置的起因对象与自身相等则抛出异常
if (cause == this)
throw new IllegalArgumentException("Self-causation not permitted");
//设置起因对象
this.cause = cause;
//返回设置的起因的对象
return this;
}
/**
* 字符串表示形式
*/
public String toString() {
String s = getClass().getName();
String message = getLocalizedMessage();
return (message != null) ? (s + ": " + message) : s;
}
/**
* 打印出错误轨迹
*/
public void printStackTrace() {
printStackTrace(System.err);
}
/**
* 打印出错误轨迹
*/
public void printStackTrace(PrintStream s) {
synchronized (s) {
//调用当前对象的toString方法
s.println(this);
//获取异常轨迹数组
StackTraceElement[] trace = getOurStackTrace();
//打印出每个元素的字符串表示
for (int i=0; i < trace.length; i++)
s.println("\tat " + trace[i]);
//获取起因对象
Throwable ourCause = getCause();
//递归的打印出起因对象的信息
if (ourCause != null)
ourCause.printStackTraceAsCause(s, trace);
}
}
/**
* 打印起因对象的信息
* @param s 打印的流
* @param causedTrace 有此对象引起的异常的异常轨迹
*/
private void printStackTraceAsCause(PrintStream s,
StackTraceElement[] causedTrace)
{
//获得当前的异常轨迹
StackTraceElement[] trace = getOurStackTrace();
//m为当前异常轨迹数组的最后一个元素位置,
//n为当前对象引起的异常的异常轨迹数组的最后一个元素
int m = trace.length-1, n = causedTrace.length-1;
//分别从两个数组的后面做循环,如果相等则一直循环,直到不等或数组到头
while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
m--; n--;
}
//相同的个数
int framesInCommon = trace.length - 1 - m;
//打印出不同的错误轨迹
s.println("Caused by: " + this);
for (int i=0; i <= m; i++)
s.println("\tat " + trace[i]);
//如果有相同的则打印出相同的个数
if (framesInCommon != 0)
s.println("\t... " + framesInCommon + " more");
//获得此对象的起因对象,并递归打印出信息
Throwable ourCause = getCause();
if (ourCause != null)
ourCause.printStackTraceAsCause(s, trace);
}
/**
* 打印出错误轨迹
*/
public void printStackTrace(PrintWriter s) {
synchronized (s) {
s.println(this);
StackTraceElement[] trace = getOurStackTrace();
for (int i=0; i < trace.length; i++)
s.println("\tat " + trace[i]);
Throwable ourCause = getCause();
if (ourCause != null)
ourCause.printStackTraceAsCause(s, trace);
}
}
/**
* 打印起因对象的信息
*/
private void printStackTraceAsCause(PrintWriter s,
StackTraceElement[] causedTrace)
{
// assert Thread.holdsLock(s);
// Compute number of frames in common between this and caused
StackTraceElement[] trace = getOurStackTrace();
int m = trace.length-1, n = causedTrace.length-1;
while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
m--; n--;
}
int framesInCommon = trace.length - 1 - m;
s.println("Caused by: " + this);
for (int i=0; i <= m; i++)
s.println("\tat " + trace[i]);
if (framesInCommon != 0)
s.println("\t... " + framesInCommon + " more");
// Recurse if we have a cause
Throwable ourCause = getCause();
if (ourCause != null)
ourCause.printStackTraceAsCause(s, trace);
}
/**
* 填充异常轨迹
*/
public synchronized native Throwable fillInStackTrace();
/**
* 返回当前的异常轨迹的拷贝
*/
public StackTraceElement[] getStackTrace() {
return (StackTraceElement[]) getOurStackTrace().clone();
}
/**
* 获取当前的异常轨迹
*/
private synchronized StackTraceElement[] getOurStackTrace() {
//如果第一次调用此方法则初始化异常轨迹数组
if (stackTrace == null) {
//获得异常轨迹深度
int depth = getStackTraceDepth();
//创建新的异常轨迹数组,并填充它
stackTrace = new StackTraceElement[depth];
for (int i=0; i < depth; i++)
stackTrace[i] = getStackTraceElement(i);//获取指定位标的异常轨迹
}
return stackTrace;
}
/**
* 设置异常轨迹
*/
public void setStackTrace(StackTraceElement[] stackTrace) {
//拷贝设置参数
StackTraceElement[] defensiveCopy =
(StackTraceElement[]) stackTrace.clone();
//如果设置参数有空元素则抛出异常
for (int i = 0; i < defensiveCopy.length; i++)
if (defensiveCopy[i] == null)
throw new NullPointerException("stackTrace[" + i + "]");
//设置当前对象的异常轨迹
this.stackTrace = defensiveCopy;
}
/**
* 异常轨迹的深度,0表示无法获得
*/
private native int getStackTraceDepth();
/**
* 获取指定位标的异常轨迹
*/
private native StackTraceElement getStackTraceElement(int index);
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws IOException
{
getOurStackTrace();
s.defaultWriteObject();
}
}
异常处理类-Throwable源码详解的更多相关文章
- JUC锁:核心类AQS源码详解
目录 1 疑点todo和解疑 2 AbstractQueuedSynchronizer学习总结 2.1 AQS要点总结 2.2 细节分析 2.2.1 插入节点时先更新prev再更新前驱next 2.2 ...
- spring事务详解(三)源码详解
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...
- Shiro 登录认证源码详解
Shiro 登录认证源码详解 Apache Shiro 是一个强大且灵活的 Java 开源安全框架,拥有登录认证.授权管理.企业级会话管理和加密等功能,相比 Spring Security 来说要更加 ...
- Activiti架构分析及源码详解
目录 Activiti架构分析及源码详解 引言 一.Activiti设计解析-架构&领域模型 1.1 架构 1.2 领域模型 二.Activiti设计解析-PVM执行树 2.1 核心理念 2. ...
- 源码详解系列(七) ------ 全面讲解logback的使用和源码
什么是logback logback 用于日志记录,可以将日志输出到控制台.文件.数据库和邮件等,相比其它所有的日志系统,logback 更快并且更小,包含了许多独特并且有用的特性. logback ...
- RocketMQ源码详解 | Producer篇 · 其二:消息组成、发送链路
概述 在上一节 RocketMQ源码详解 | Producer篇 · 其一:Start,然后 Send 一条消息 中,我们了解了 Producer 在发送消息的流程.这次我们再来具体下看消息的构成与其 ...
- RocketMQ源码详解 | Broker篇 · 其一:线程模型与接收链路
概述 在上一节 RocketMQ源码详解 | Producer篇 · 其二:消息组成.发送链路 中,我们终于将消息发送出了 Producer,在短暂的 tcp 握手后,很快它就会进入目的 Broker ...
- RocketMQ源码详解 | Consumer篇 · 其一:消息的 Pull 和 Push
概述 当消息被存储后,消费者就会将其消费. 这句话简要的概述了一条消息的最总去向,也引出了本文将讨论的问题: 消息什么时候才对被消费者可见? 是在 page cache 中吗?还是在落盘后?还是像 K ...
- 条件随机场之CRF++源码详解-预测
这篇文章主要讲解CRF++实现预测的过程,预测的算法以及代码实现相对来说比较简单,所以这篇文章理解起来也会比上一篇条件随机场训练的内容要容易. 预测 上一篇条件随机场训练的源码详解中,有一个地方并没有 ...
随机推荐
- Jedis & spring-data-redis
当我们了解了redis的五大数据类型,手动去敲一敲每个数据类型对应的命令,无论是再来看jedis,还是spring-data-redis都是很轻松的,他们提供的API都是基于原生的redis命令,可读 ...
- SpringCloud的入门学习之Eureka(高可用注册中心HA)构建Provider服务、Consumer服务
1.在高可用的Eureka注册中心中构建provider服务. 使用springboot的多环境配置,来搭建Eureka的高可用集群式部署.由于使用的是maven构建的springboot项目,所以首 ...
- .net core使用HttpClient发送代理请求_程序内抓包_Fiddler抓包
前言: 通过Fiddler抓取浏览器请求数据,相信大家已经都会用了,我们知道Fiddler是通过在本机计算器添加一个默认的代理服务器来实现的抓包数据的,端口号为:8888. 其实当我们打开Fiddl ...
- Scrapy框架的简单使用
一.安装依赖 #Windows平台 1.pip3 install wheel 3.pip3 install lxml 4.pip3 install pyopenssl 5.pip3 install p ...
- linux基本命令的操作
---恢复内容开始--- ----------------------------=========================文件与目录操作cd /home 进入’/homw’目录cd … 返回 ...
- 利用Azure虚拟机安装Dynamics 365 Customer Engagement之十一:SQL Server配置Always On后D365的配置更改
我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...
- arcgis api 4.x for js 图层拓展篇之mapvLayer(附源码下载)
因为在项目开发过程中,使用的arcgis js api版本是4.7,并不能支持客户端渲染热力图,想到arcgis js api 4.x的渲染是基于canvas,故琢磨着是否能借助类似于mapV.ech ...
- 从0系统学Android-2.4 Activity 的生命周期
本系列文章,参考<第一行代码>,作为个人笔记 更多内容:更多精品文章分类 本系列持续更新中.... 2.4 Activity 的生命周期 掌握 Activity 的生命周期对于开发者来说是 ...
- mssql 系统函数 字符串函数 space 功能简介
转自: http://www.maomao365.com/?p=4672 一.space 函数功能简介 space功能:返回指定数量的空格参数简介: 参数1: 指定数量,参数需为int类型 注意事项 ...
- Druid-代码段-4-2
所属文章:池化技术(一)Druid是如何管理数据库连接的? 本代码段对应流程4.1,连接池瘦身: //连接池瘦身 public void shrink(boolean checkTime, boole ...