Java的Exception简介

目录

一,关于Throwable,Exception,Error

Throwable类

Error类

Exception类

关于cause

二,Throwable类中的方法和说明

1,fillInStackTrace()

2,getCause()

3,initCause()

4,getMessage()

5,getLocalizedMessage()

6,printStackTrace()

7,getStackTrace()


一,关于Throwable,Exception,Error

要介绍Exception,首先要看看Exception在Java语言中的位置,下图是Exception的大家庭:

可以看到,Java语言中所有错误和异常的超类是Throwable类,他有两个子类:Error类(异常)和Exception类(错误),Error类和Exception类各自还有无穷无尽的子类和后代。

 

Throwable类

Throwable类是Java语言中所有错误和异常的超类,异常和错误中的很多方法都是从该类继承来的,比如最常用的e.printStackTrace什么的,这个类有以下两个主要特点:

1,可抛。正如类名所示,Throwable类的实例,或者其子类、后代的实例,可以在throw语句中向上层抛出,就像这样:

throw new Throwable();

2,可接。能抛出自然能接到,Throwable类的实例,或者其子类、后代的实例,可以在catch语句中捕获。

另外,从JDK1.7开始,一行catch语句可以包含多个Throwable类型了。

 

Error类

Error类代表错误,代表Java程序运行时发生的严重问题,通常情况下出现Error时连catch都没有必要。在Error的子类中,ThreadDeath类的情节相对较轻,但也不建议在程序中捕获这个错误,具体说明可以参考Java的API文档。

Error类的子类有以下这些:

 

Exception类

主角登场,Exception类,他代表异常,代表Java程序在正常运行期间发生并意图捕获的场景(或者说条件)。

和Error类不同,Exception类代表了合理的、可控的、需要在代码中写明处理方法的场景。

Exception类并没有比他的父类Throwable多写多少方法。

Exception的子类就多了:

可以看到,我们平时常见的多数异常,比如空指针异常NullPointerException……并不在这个列表中,因为NullPointerException是RuntimeException的子类。

 

所以,如果你想在代码里抛点什么,可以使用Throwable类或Exception类(和Exception类的后代),或者干脆自定义一个类来继承他们。

Error类还是不要继承了,Java可能并不喜欢你这么做。

 

关于cause

Java的Throwable有cause的概念,看Java的API文档感觉有点晦涩难懂,研究了一下大概是这样的:

cause指的是引发Throwable的原因,这个原因也是一个Throwable实例,每个Throwable都可以有cause。

鉴于Throwable的cause也是一个Throwable实例,所以这个作为cause的Throwable实例也可以有cause,cause包含cause这件事一直延续下去,就有了异常链的概念。

cause概念的建立,一方面是为了包装底层的异常,另一方面是为了抛出自己想要的异常,而不是底层实际的那个异常。

想给一个Throwable实例指定cause,有两种方式:在构造中指定和在initCause(Throwable cause)方法中指定

1,在构造中指定。

从Throwable类开始,就有这样的构造:

Throwable(String message, Throwable cause)

Throwable(Throwable cause)

Throwable类的子类们也有很多可以使用这样的构造,如果用这种方式创建Throwable实例,其中的cause参数就会成为实例的cause。

比如:

Throwable throwable=new Throwable(new NullPointerException());
System.out.println(throwable.getCause());

输出的结果是:

java.lang.NullPointerException

新建的NullPointerException实例就是throwable实例的cause。

2,在initCause(Throwable cause)方法中指定。

initCause(Throwable cause)方法是由Throwable类实现的,子类们也可以直接使用,比如:

Throwable throwable2=new Throwable();
throwable2.initCause(new NullPointerException());
System.out.println(throwable2.getCause());

输出的结果是:

java.lang.NullPointerException

 

 

二,Throwable类中的方法和说明

1,fillInStackTrace()

官方说明是:在异常堆栈跟踪中填充。

看不懂。

这个方法的实际功能是这样的:以调用该方法的代码位置作为调用栈的顶端,重新填充异常的调用栈信息

意即:不管多底层抛出来的异常,我这调一下这个方法,我这就成调用栈顶端了,再printStackTrace的时候就看不见底层的调用栈了。

举个例子:

public static void main(String[] args) {
	try {
		Throwable th=testA();
		th.fillInStackTrace();
		th.printStackTrace();//此处打印第三个异常调用栈信息
	} catch (Throwable e) {
		e.printStackTrace();
	}
	
}
	
public static Throwable testA() throws Throwable {
	try {
		testB();
	} catch (Exception e) {
		e.printStackTrace();//此处打印第一个异常调用栈信息
		e=(Exception) e.fillInStackTrace();
		e.printStackTrace();//此处打印第二个异常调用栈信息
		return e;
	}
	return null;
}

public static void testB() throws Throwable{
	throw new NullPointerException();
}

输出的结果是这样的:

java.lang.NullPointerException

         at test.ExceptionTest2.testB(ExceptionTest2.java:37)

         at test.ExceptionTest2.testA(ExceptionTest2.java:26)

         at test.ExceptionTest2.main(ExceptionTest2.java:14)

java.lang.NullPointerException

         at test.ExceptionTest2.testA(ExceptionTest2.java:29)

         at test.ExceptionTest2.main(ExceptionTest2.java:14)

java.lang.NullPointerException

         at test.ExceptionTest2.main(ExceptionTest2.java:15)

解析一下,异常从testB()方法开始,并把这个异常抛给testA()方法。

testA()方法的catch代码第一次打印了异常的原始信息:

java.lang.NullPointerException

         at test.ExceptionTest2.testB(ExceptionTest2.java:37)

         at test.ExceptionTest2.testA(ExceptionTest2.java:26)

         at test.ExceptionTest2.main(ExceptionTest2.java:14)

 

然后在testA()方法的catch代码块中调用fillInStackTrace(),这样testA()方法就成了调用栈顶端,所以第二次打印的异常信息就是这样的:

java.lang.NullPointerException

         at test.ExceptionTest2.testA(ExceptionTest2.java:29)

         at test.ExceptionTest2.main(ExceptionTest2.java:14)

testA()方法把异常用返回值的形式返回给了main()方法,然后main()方法调用fillInStackTrace()方法,于是main()方法成了这个异常的调用栈的顶端,于是第三次打印的异常信息就是这样的:

java.lang.NullPointerException

         at test.ExceptionTest2.main(ExceptionTest2.java:15)

还是那句话,哪儿调用哪儿就变成顶端,不论异常是throw抛出的,还是用返回值返回的。

 

另外,这个方法是有返回值的,返回类型是Throwable,其实返回的就是调用这个方法的Throwable本身。

然鹅,即使是一个Exception实例来调用这个方法,返回值也是个Throwable,如果你真打算这么写:

e=(Exception) e.fillInStackTrace();

那么强制类型转换是必要的。

其实我没怎么理解这个方法的返回值有什么意义,因为当实例e调用这个方法时,返回值就是实例e本身,所以我完全可以简单的使用:

e.fillInStackTrace();

代码来刷新实例e的调用栈,而不需要拿到返回值,类型转换,再赋值给e自己,可能Java的设计者有什么其他的想法吧。

 

2,getCause()

如上文所说,这个方法用于获得Throwable的cause,如果没有cause则返回null。

 

3,initCause()

如上文所说,这个方法用于给Throwable实例指定cause。

API文档中说,这个方法只能调用一次,而且如果已经在构造里指定了cause,甚至一次也不能调用。

其实意思是说,如果一个Throwable实例已经有了cause,再调用这个方法时会报错

比如:

Throwable a=new Throwable(new NullPointerException());
a.initCause(new NullPointerException());
throw a;

会报错:

java.lang.IllegalStateException: Can't overwrite cause with java.lang.NullPointerException

         at java.lang.Throwable.initCause(Throwable.java:456)

         at test.ExceptionTest2.testB(ExceptionTest2.java:38)

         at test.ExceptionTest2.testA(ExceptionTest2.java:26)

         at test.ExceptionTest2.main(ExceptionTest2.java:14)

Caused by: java.lang.Throwable: java.lang.NullPointerException

         at test.ExceptionTest2.testB(ExceptionTest2.java:37)

         ... 2 more

再比如:

Throwable a=new Throwable();
a.initCause(new NullPointerException());
a.initCause(new NullPointerException());

会报错:

java.lang.IllegalStateException: Can't overwrite cause with java.lang.NullPointerException

         at java.lang.Throwable.initCause(Throwable.java:456)

         at test.ExceptionTest2.testB(ExceptionTest2.java:39)

         at test.ExceptionTest2.testA(ExceptionTest2.java:26)

         at test.ExceptionTest2.main(ExceptionTest2.java:14)

Caused by: java.lang.Throwable

         at test.ExceptionTest2.testB(ExceptionTest2.java:37)

         ... 2 more

这样的设定可能是有关于异常链的考虑。

 

4,getMessage()

该方法用于得到一个Throwable实例的详细消息字符串。

设定这个字符串可以用以下构造:

Throwable(String message)

Throwable(String message, Throwable cause)

设置了message参数,就可以用getMessage()方法得到。

 

5,getLocalizedMessage()

该方法默认情况下和getMessage()功能相同,不过可以在自定义的Throwable子类中重写,输出自己想要的内容。

 

6,printStackTrace()

该方法用于将Throwable实例的信息输出到错误输出流,同System.err。

输出的内容包括:

1,第一行,Throwable实例调用toString()后的结果。

2,由fillInStackTrace()记录的调用栈信息。

3,cause信息。

 

7,getStackTrace()

异常的调用栈信息会被放在一个数组中,数组的第一个元素是调用栈的顶端,代表最后的方法调用。

这个方法用于返回这个调用栈信息数组。返回值类型是:StackTraceElement[]

比如这样的代码:

try {
         testA();
} catch (Throwable e) {
         e.printStackTrace();
         System.out.println("========================");
         StackTraceElement[] elements=e.getStackTrace();
         for(int i=0;i<elements.length;i++){
                   StackTraceElement element=elements[i];
                   System.out.println(element);
         }
}

输出是这样的:

java.lang.Throwable

         at test.ExceptionTest.testB(ExceptionTest.java:26)

         at test.ExceptionTest.testA(ExceptionTest.java:22)

         at test.ExceptionTest.main(ExceptionTest.java:8)

========================

test.ExceptionTest.testB(ExceptionTest.java:26)

test.ExceptionTest.testA(ExceptionTest.java:22)

test.ExceptionTest.main(ExceptionTest.java:8)

 

以上

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值