Throwable类

您所在的位置:网站首页 java的throwable类 Throwable类

Throwable类

2023-10-20 22:08| 来源: 网络整理| 查看: 265

1.Throwable

Throwable类实现了Serializable接口

 Throwable类是 Java 语言中所有错误和异常的超类。只有作为此类(或其子类之一)实例的对象才会被 Java 虚拟机抛出,或者可以被 Java throw语句抛出。同样,只有此类或其子类之一可以是catch子句中的参数类型。出于对异常的编译时检查的目的, Throwable和任何不是RuntimeException或Error的子类的Throwable子类都被视为已检查异常。两个子类的实例Error和Exception通常用于指示发生了异常情况。通常,这些实例是在异常情况的上下文中新创建的,以便包含相关信息(例如堆栈跟踪数据)。throwable 包含其线程在创建时的执行堆栈的快照。它还可以包含提供有关错误的更多信息的消息字符串。随着时间的推移,一个 throwable 可以抑制其他 throwable 的传播。最后,throwable 还可以包含一个原因:另一个 throwable 导致这个 throwable 被构造。这种因果信息的记录被称为链式异常设施,因为原因本身可以有一个原因,依此类推,导致异常“链”,每个异常都由另一个引起。throwable 可能有原因的一个原因是抛出它的类是构建在较低层抽象之上的,并且由于较低层中的失败而导致上层上的操作失败。让下层抛出的 throwable 向外传播是不好的设计,因为它通常与上层提供的抽象无关。此外,这样做会将上层的 API 与其实现的细节联系起来,假设下层的异常是已检查异常。抛出“包装异常”(即,包含原因的异常)允许上层将失败的细节传达给其调用者,而不会产生这些缺点中的任何一个。它保留了更改上层实现的灵活性,而无需更改其 API(特别是其方法引发的异常集)。throwable 可能有原因的第二个原因是,抛出它的方法必须符合不允许该方法直接抛出原因的通用接口。例如,假设一个持久化集合符合Collection接口,并且它的持久性是在java.io之上实现的。假设add方法的内部可以抛出IOException 。该实现可以将IOException的详细信息传达给其调用者,同时通过将IOException包装在适当的未经检查的异常中来符合Collection接口。 (持久化集合的规范应该表明它能够抛出这样的异常。)原因可以通过两种方式与 throwable 关联:通过将原因作为参数的构造函数,或通过initCause(Throwable)方法。希望允许原因与它们关联的新 throwable 类应提供采用原因的构造函数,并将(可能间接)委托给采用原因的Throwable函数之一。因为initCause方法是公共的,所以它允许一个 cause 与任何 throwable 相关联,甚至是一个“legacy throwable”,其实现早于将异常链接机制添加到Throwable 。按照惯例, Throwable类及其子类有两个构造函数,一个不带参数,另一个带可用于生成详细消息的String参数。此外,那些可能有相关原因的子类应该有另外两个构造函数,一个采用Throwable (原因),另一个采用String (详细消息)和Throwable (原因)。

2.使用

因为此类是所有异常的超类,我们先看一个常见的异常,用try、catch捕获并打印异常信息

package com.itheima.domain; public class Test { @org.junit.Test public void setE() { try { int i = 1/0; }catch (Exception e) { System.out.println(e); } } }

 java.lang.ArithmeticException: / by zero

再看以Throwable捕获的情况

package com.itheima.domain; public class Test { @org.junit.Test public void setE() { try { int i = 1/0; }catch (Throwable e) { System.out.println(e); } } }

java.lang.ArithmeticException: / by zero

发现是一样的,那么两者到底有什么区别呢?

throwable和exception的区别:

1、throwable是父类,exception是子类。

2、throwable是根基,exception是从throwable派生出来的。

3、throwable中包括exception(异常)和error(错误)。

4、throwable用来定义所有可以作为异常被抛出来的类,exception专指程序本身可以处理的异常,一般性的异常。

在Java程序中,所有异常对象的根基类是Throwable,Throwable从Object直接继承而来(这是Java系统所强制要求的)。Throwable有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。

可以看到,error也是由throwable派生而来的,那么我们不妨抛出一个error查看一下捕获异常的信息

package com.itheima.domain; public class Test { @org.junit.Test public void setE() { try { throw new Error("这是一个Error"); }catch (Throwable e) { System.out.println(e); } } }

java.lang.Error: 这是一个Error

好的没问题,确实是可以接收error的

3.throwable的参数和方法  1.serialVersionUID private static final long serialVersionUID = -3042686055658047285L;

先看序列化与反序列化成功的案例

package com.itheima.domain; import java.io.*; public class my { @org.junit.Test public void test() throws IOException, ClassNotFoundException { Test test = new Test(); test.setName("test"); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream; objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(test); String string = byteArrayOutputStream.toString("ISO-8859-1"); objectOutputStream.close(); byteArrayOutputStream.close(); System.out.println("序列化前:"+test.toString()); System.out.println("序列化后:"+string); test.setSerialVersionUID(2L); Test test2 = new Test(); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(string.getBytes("ISO-8859-1")); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); test2= (Test) objectInputStream.readObject(); objectInputStream.close(); byteArrayInputStream.close(); System.out.println("反序列化后:"+test2.toString()); } } 反序列化成功 序列化前:Test{serialVersionUID=1, name='test'} 序列化后:¬í sr com.itheima.domain.TestP8‹ detailMessageq ~ [ stackTracet [Ljava/lang/StackTraceElement;L suppressedExceptionst Ljava/util/List;xpq ~ pur [Ljava.lang.StackTraceElement; methodNameq ~ L 反序列化后:Test{serialVersionUID=1, name='test'}

再看一下序列化与反序列化失败的情况

package com.itheima.domain; import java.io.*; public class my { @org.junit.Test public void test() throws IOException, ClassNotFoundException { Test test = new Test(); test.setName("test"); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream; objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(test); String string = byteArrayOutputStream.toString("GBK"); objectOutputStream.close(); byteArrayOutputStream.close(); System.out.println("序列化前:"+test.toString()); System.out.println("序列化后:"+string); test.setSerialVersionUID(2L); Test test2 = new Test(); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(string.getBytes("GBK")); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); test2= (Test) objectInputStream.readObject(); objectInputStream.close(); byteArrayInputStream.close(); System.out.println("反序列化后:"+test2.toString()); } } 序列化前:Test{serialVersionUID=1, name='test'} 序列化后: sr com.itheima.domain.TestP8� detailMessageq ~ [ lineNumberL classLoaderNameq ~ L declaringClassq ~ LfileNameq ~ L methodNameq ~ L java.io.InvalidClassException: com.itheima.domain.Test; local class incompatible: stream classdesc serialVersionUID = 5780439436189254998, local class serialVersionUID = 5780522999072965974

可以看到序列化失败情况下UID是不同的,可以说UID是标识序列化前后是否是一个类的。

serialVersionUID适用于java序列化机制。简单来说,JAVA序列化的机制是通过 判断类的serialVersionUID来验证的版本一致的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID于本地相应实体类的serialVersionUID进行比较。如果相同说明是一致的,可以进行反序列化,否则会出现反序列化版本一致的异常,即是InvalidCastException。

具体序列化的过程是这样的:序列化操作时会把系统当前类的serialVersionUID写入到序列化文件中,当反序列化时系统会自动检测文件中的serialVersionUID,判断它是否与当前类中的serialVersionUID一致。如果一致说明序列化文件的版本与当前类的版本是一样的,可以反序列化成功,否则就失败;

 2.backtrace private transient Object backtrace;

说明:本机代码在此插槽中保存了一些堆栈回溯的指示,此对象不可序列化。

transient关键字

在实际开发过程中,我们常常会遇到这样的问题,这个类的有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。

总之,java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。

3.Throwable private Throwable cause = this;

为了让 Throwable 对象成为不可变对象并被 JVM 安全地重用,例如 OutOfMemoryErrors,Throwable 的字段可写以响应用户操作、cause、stackTrace 和 suppressExceptions

遵循以下协议:1) 将字段初始化为非空标记值,表示逻辑上未设置该值。 2) 向该字段写入空值表示禁止进一步写入 3) 可以将标记值替换为另一个非空值。例如,HotSpot JVM 的实现已经预先分配了 OutOfMemoryError 对象,以便更好地诊断这种情况。这些对象是在不调用该类的构造函数的情况下创建的,并且相关字段被初始化为 null。为了支持此功能,添加到 Throwable 的任何需要初始化为非空值的新字段都需要协调 JVM 更改。导致此 throwable 被抛出的 throwable,如果此 throwable 不是由另一个 throwable 引起,或者原因 throwable 未知,则为 null。如果这个字段和这个 throwable 本身相等,说明这个 throwable 的原因还没有被初始化。

导致此 throwable 被抛出的 throwable,如果此 throwable 不是由另一个 throwable 引起,或者原因 throwable 未知,则为 null。如果这个字段和这个 throwable 本身相等,说明这个 throwable 的原因还没有被初始化;

4.detailMessage private String detailMessage;

这是对于Throwable的说明变量

看一下Throwable 的构造函数:

public Throwable() { fillInStackTrace(); }

这是默认的无参构造方式

public Throwable(String message) { fillInStackTrace(); detailMessage = message; }

当我们想要给其一个说明时可使用此方式,以下为例子:

package com.itheima.domain; import org.junit.Test; public class my { @Test public void test(){ Throwable throwable1 = new Throwable("我的throwable"); System.out.println(throwable1.getMessage()); } }

我的throwable

控制台打印出了我们定义的信息

 



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3