1、java提供的异常不可能预见所有的问题,所以需要自己定义异常类,必须从已有的异常类继承,最好选择意思相近的异常类继承。

class MyException extends Exception{}

public class Tree1 {

    public static void f() throws MyException{
System.out.println("throws MyException from f()");
throw new MyException();
} public static void main (String[] args) { try {
f();
}catch(MyException e){
System.out.println("caught it");
}
}
}

try块中的代码将被监控,catch将会接受来自try块的异常。这里的f()方法将会抛出一个 MyException类的异常,然后catch将会接收到这个异常,并输出caught it4

所以输出结果为:

throws MyException from f()
caught it

可以为异常类定义一个接受字符串参数的构造器:

class MyException extends Exception{
public MyException() {}
public MyException(String msg) {
super(msg);
}
}
public class Tree1 {
public static void f() throws MyException{
System.out.println("throws MyException from f()");
throw new MyException();
} public static void main (String[] args) {
try {
f();
}catch(MyException e){
e.printStackTrace(System.out);
}
}
}

这样的输出是:

throws MyException from f()
MyException
at Tree1.f(Tree1.java:11)
at Tree1.main(Tree1.java:16)

在异常类的定义中的第二个构造器中使用了super关键字明确调用了其基类构造器,它接受一个字符串作为参数。

在异常处理程序中,调用了Throwable类声明的printStackTrace()方法,就像输出中看到的这样,它将会打印“从方法调用处直到异常抛出处” 的方法调用序列,这里信息发送到了System.out,如果使用默认的e.printStackTrace();则信息将被输出到标准错误流。

2、Exception类型的方法

class MyException extends Exception{
public MyException() {}
public MyException(String msg) {
super(msg);
}
}
class MySecondException extends Exception{
public MySecondException() {}
public MySecondException(String msg) {
super(msg);
}
}
public class Tree1 {
public static void f() throws MyException {
System.out.println("throws MyException from f()");
throw new MyException("name");
} public static void g() throws MySecondException {
System.out.println("throws MySecondException from g()");
throw new MySecondException("name2");
} public static void main (String[] args){
try {
f();
// g();
}catch(Exception e){
System.out.println(e.getMessage());
System.out.println(e);
System.out.println(e.getLocalizedMessage());
}
}
}

这里定义了两个继承自Exception的异常类,分别是MyException、MySecondException,由两个方法f()、g()抛出,如果在try块中只有f();,输出结果为:

throws MyException from f()
name
MyException: name
name

Throwable类的getMessage()方法返回的是Exception的详细消息字符串,就是抛出这个异常时候传入的字符串,

而getLocalizedMessage()方法返回的是 Exception的本地化描述。

toString()方法返回 此对象的类的 name ": "(冒号和一个空格)

然后如果把上面代码g();的前面的//删掉,就是try块中将运行f()和g()两个方法,输出结果为:

throws MyException from f()
name
MyException: name
name

和刚才一样这是因为catch接收到异常后就会结束try块中的程序运行,所以g()方法并没有被运行,所以如果先运行g()的结果就是:

throws MySecondException from g()
name2
MySecondException: name2
name2

3、栈轨迹

public class Tree1 {
public static void f(){
try {
throw new Exception();
}catch(Exception e){
e.printStackTrace();
}
} public static void g() {f();}
public static void h() {g();} public static void main (String[] args){
f();
g();
h();
}
}

输出结果为:

java.lang.Exception
at Tree1.f(Tree1.java:17)
at Tree1.main(Tree1.java:27)
java.lang.Exception
at Tree1.f(Tree1.java:17)
at Tree1.g(Tree1.java:23)
at Tree1.main(Tree1.java:28)
java.lang.Exception
at Tree1.f(Tree1.java:17)
at Tree1.g(Tree1.java:23)
at Tree1.h(Tree1.java:24)
at Tree1.main(Tree1.java:29)

这里的调用的printStackTrace(),是Throwable类的方法,这个方法会将Throwable对象的栈轨迹信息打印到标准错误输出流上,第一行是异常类的tostring()方法输出的内容,后面几行的内容都是之前通过fillInStackTrace()方法保存的内容。

java.lang.Exception
at Tree1.f(Tree1.java:17)
at Tree1.main(Tree1.java:27)

在这个例子中,在方法f()中抛出异常,在main方法中捕获异常,并且打印栈轨迹信息。因此,输出依次展示了f—>main的过程。还打印了抛出错误,捕获错误的行数、类的名字。

java.lang.Exception
at Tree1.f(Tree1.java:17)
at Tree1.g(Tree1.java:23)
at Tree1.main(Tree1.java:28)

这里就是在方法f()中抛出异常,方法g()中调用了f(),然后和上一个一样了,第三个也同样。

public class Tree1 {
public static void f(){
try {
throw new Exception();
}catch(Exception e){
for(StackTraceElement ste: e.getStackTrace()) {
System.out.println(ste); }
}
} public static void g() {f();}
public static void h() {g();} public static void main (String[] args){
f();
System.out.println("------------------");
g();
System.out.println("------------------");
h();
}
}

这个例子中调用了getStackTrace()方法,这个方法返回StackTraceElement类的一个对象。其输出内容为:

Tree1.f(Tree1.java:17)
Tree1.main(Tree1.java:30)
------------------
Tree1.f(Tree1.java:17)
Tree1.g(Tree1.java:26)
Tree1.main(Tree1.java:32)
------------------
Tree1.f(Tree1.java:17)
Tree1.g(Tree1.java:26)
Tree1.h(Tree1.java:27)
Tree1.main(Tree1.java:34)

如果这样使用:

public class Tree1 {
public static void f(){
try {
throw new Exception();
}catch(Exception e){
for(StackTraceElement ste: e.getStackTrace()) {
System.out.print(ste.getMethodName() + " " );
System.out.println(ste.getLineNumber());
}
}
} public static void g() {f();}
public static void h() {g();} public static void main (String[] args){
f();
System.out.println("------------------");
g();
System.out.println("------------------");
h();
}
}

调用StackTraceElement中的方法getMethodName()和getLineNumber()就可以值获取栈轨迹中的方法 和行:

f  17
main 30
------------------
f 17
g 26
main 32
------------------
f 17
g 26
h 27
main 34

所以,其实StackTraceElement是一个栈轨迹元素的数组。将这些栈轨迹元素保存在一个数组中。每个元素对应栈的一个栈帧。数组的第一个元素保存的是栈顶元素,也就是上面的f。最后一个元素保存的栈底元素,也就是main。

public class Tree1 {
public static void f() throws Exception{
throw new Exception();
} public static void g() throws Exception {
try {
f();
}catch(Exception e){
e.printStackTrace();
throw e;
}
} public static void main (String[] args){
try {
g();
}catch(Exception e){
e.printStackTrace();
}
}
}

4、重新抛出异常

这里f()函数中抛出一个异常,然后g()方法中捕获了这个异常并打印异常栈轨迹Stack Trace,然后又再抛出了刚刚的异常,mai方法中捕获 了这个异常并打印异常栈轨迹Stack Trace,所以结果为:

java.lang.Exception
at Tree1.f(Tree1.java:16)
at Tree1.g(Tree1.java:21)
at Tree1.main(Tree1.java:30)
java.lang.Exception
at Tree1.f(Tree1.java:16)
at Tree1.g(Tree1.java:21)
at Tree1.main(Tree1.java:30)

也就是说,捕获到异常又立即抛出,在上级方法调用中再次捕获这个异常,打印的栈轨迹信息是一样的。额,其实只看代码也知道,因为这里只是把刚刚异常e又抛出一次,

public class Tree1 {
public static void f() throws Exception{
throw new Exception();
} public static void g() throws Exception {
try {
f();
}catch(Exception e){
e.printStackTrace();
throw (Exception)e.fillInStackTrace();
}
} public static void main (String[] args){
try {
g();
}catch(Exception e){
e.printStackTrace();
}
}
}

throw (Exception)e.fillInStackTrace();

这一行调用了Exception的fillInStackTrace()方法,首先要知道其实这个方法并不是来自于Exception类。Exception类本身除了定义了几个构造器之外,所有的方法都是从其父类继承过来的。而和异常相关的方法都是从java.lang.Throwable类继承过来的,所以其实fillInStackTrace()是Throwable类的方法,然后fillInStackTrace()方法就是将当前线程当前状态下的轨迹栈的状态保存进Throwabe中,就是更新的意思。

public Throwable fillInStackTrace()

这是这个方法的原型所以它的返回值是一个Throwable类对象,所以使用它更新的时候需要强制类型转换。

throw (Exception)e.fillInStackTrace();

所以输出内容为:

java.lang.Exception
at Tree1.f(Tree1.java:16)
at Tree1.g(Tree1.java:21)
at Tree1.main(Tree1.java:30)
java.lang.Exception
at Tree1.g(Tree1.java:24)
at Tree1.main(Tree1.java:30)

这次第二个打印的栈轨迹信息就没有f了。

5、异常链

class MyException1 extends Exception{} 

class MyException2 extends Exception{}

public class Tree1 {

    public static void f() throws MyException1{
throw new MyException1();
} public static void g() throws MyException2{
try {
f();
} catch (MyException1 e) {
e.printStackTrace();
throw new MyException2();
}
} public static void main (String[] args){
try {
g();
}catch(Exception e){
e.printStackTrace();
}
}
}

这里定义了两个异常类,f()方法抛出了MyException1,g()方法捕获了这个异常并打印了异常的栈轨链,然后抛出了另一个异常MyException2也打印了异常的栈轨链,所以输出结果为:

MyException1
at Tree1.f(Tree1.java:16)
at Tree1.g(Tree1.java:21)
at Tree1.main(Tree1.java:31)
MyException2
at Tree1.g(Tree1.java:24)
at Tree1.main(Tree1.java:31)

这没什么毛病,但是常常想要在捕获一个异常后抛出另一个异常,并且希望把原始异常的信息保存下来,这就需要将原始异常的信息包装在新的异常中,这被称为异常链

class MyException1 extends Exception{} 

class MyException2 extends Exception{
MyException2(Throwable throwable){
super(throwable);
}
MyException2(){
super();
}
}
public class Tree1 { public static void f() throws MyException1{
throw new MyException1();
} public static void g() throws MyException2{
try {
f();
} catch (MyException1 e) {
e.printStackTrace();
throw new MyException2(e);
}
} public static void main (String[] args){
try {
g();
}catch(Exception e){
e.printStackTrace();
}
}
}

这样的输出结果就是:

MyException1
at Tree1.f(Tree1.java:16)
at Tree1.g(Tree1.java:21)
at Tree1.main(Tree1.java:31)
MyException2: MyException1
at Tree1.g(Tree1.java:24)
at Tree1.main(Tree1.java:31)
Caused by: MyException1
at Tree1.f(Tree1.java:16)
at Tree1.g(Tree1.java:21)
... 1 more

这样的定义:

public class MyException2 extends Exception{
//定义异常的原因
public MyException2(String message){
super(message);
} //定义异常原因,并携带原始的异常
public MyException2(String message,Throwable cause){
super(message,cause);
} //保留原始异常信息
publicMyException2(Throwable cause){
super(cause);
}
}

就能将原始异常传递给新异常

或是:

class MyException1 extends Exception{
} class MyException2 extends Exception{
MyException2(Throwable throwable){
super(throwable);
}
MyException2(){
super();
}
} class MyException3 extends Exception{
MyException3(Throwable throwable){
super(throwable);
}
MyException3(){
super();
}
} public class Tree1 { public static void f() throws MyException1{
throw new MyException1();
} public static void g() throws MyException2{
try {
f();
} catch (MyException1 e) {
// e.printStackTrace();
throw new MyException2(e);
}
} public static void h() throws MyException3{
try {
g();
} catch (MyException2 e) {
// e.printStackTrace();
throw new MyException3(e);
}
} public static void main (String[] args){
try {
h();
}catch(Exception e){
e.printStackTrace();
}
}
}

这里值输出了最后一个异常的栈轨迹

MyException3: MyException2: MyException1
at Tree1.h(Tree1.java:44)
at Tree1.main(Tree1.java:51)
Caused by: MyException2: MyException1
at Tree1.g(Tree1.java:35)
at Tree1.h(Tree1.java:41)
... 1 more
Caused by: MyException1
at Tree1.f(Tree1.java:27)
at Tree1.g(Tree1.java:32)
... 2 more

其中还包括了MyException1和MyException2 的信息

6、异常的限制

  a、当覆盖方法的时候,只能抛出在基类方法的异常说明里列出的那些异常。

  b、异常限制对构造器不起作用

  c、当父类与接口具有相同的方法而且方法同时抛出不同的异常,这个时候是不允许的

  d、当父类的构造方法抛出异常,子类必须有一个构造方法是抛出相同异常或者此异常的父类。

  e、当父类方法没有抛出异常,子类覆盖的方法不能够抛出异常

  f、当父类方法抛出异常,子类覆盖的方法可以不抛出异常

  b和e有一点冲突,但是实际上是是因为父类构造器必须以这样或者那样的方式被调用,子类构造器的异常说明必须包含基类构造器的异常说明。

7、把“被检查的异常”转换为“不检查的异常”

import java.io.*;

class WrapCheckedExcetion{
void thorwRuntimeExcetion(int type) {
try {
switch(type) {
case 0: throw new FileNotFoundException();
case 1: throw new IOException();
case 2: throw new RuntimeException("where an I");
default: return;
}
}catch(Exception e) {
throw new RuntimeException(e);
}
}
} class SomeOtherExcption extends Exception{}
public class Tree1 {
public static void main(String[] args) {
WrapCheckedExcetion wce = new WrapCheckedExcetion();
wce.thorwRuntimeExcetion(3);
for(int i = 0; i < 4; i++) {
try {
if(i < 3)
wce.thorwRuntimeExcetion(i);
else
throw new SomeOtherExcption();
}catch(SomeOtherExcption e) {
System.out.println("SomeOtherExcption:" + e);
}catch(RuntimeException re) {
try {
throw re.getCause();
}catch(FileNotFoundException e) {
System.out.println("FileNotFoundException:" + e);
}catch(IOException e) {
System.out.println("IOException:" + e);
}catch(Throwable e) {
System.out.println("Throwable:" + e);
}
}
}
}
}

输出:

FileNotFoundException:java.io.FileNotFoundException
IOException:java.io.IOException
Throwable:java.lang.RuntimeException: where an I
SomeOtherExcption:SomeOtherExcption

这里的WrapCheckedExcetion中的thorwRuntimeExcetion可以生成不同的异常,这些异常都被捕获并包装进了RuntimeExcetion对象中,所以它们都变成了运行时异常的“cause”了。在main中可以不用try块就可以调用thorwRuntimeExcetion(),因为它并没有抛出“被检查的异常”所以这个thorwRuntimeExcetion方法就实现了把“被检查的异常”转换为“不检查的异常”

最新文章

  1. 记录一下git 的常用命令
  2. Elasticsearch——Search的基本介绍
  3. (转)Storm UI 解释
  4. GPG操作——签名验证
  5. PHP5中PDO的简单使用
  6. Python 数据类型
  7. Handling HTTP 404 Error in ASP.NET Web API
  8. 关于cocostudio加载UI json CCUIHELPER未声明问题
  9. python编码格式
  10. Linux环境下网卡配置
  11. MySql的隔离级别和锁的关系
  12. Maven构建真正的J2EE项目
  13. ffmpeg转码使用硬件加速
  14. SQL2005查询死锁的表和具体的语句
  15. python:前端(HTML)+后端(Django)+数据库(MySQL)
  16. 2018牛客网暑期ACM多校训练营(第一场)E Removal(DP)
  17. 论文阅读笔记三十四:DSSD: Deconvolutiona lSingle Shot Detector(CVPR2017)
  18. 2016年3月8日Android实习日记
  19. hdu1695 GCD 容斥原理
  20. BZOJ2815:[ZJOI2012]灾难(拓扑排序,LCA)

热门文章

  1. Azkaban Flow 2.0 使用简介
  2. Java虚拟机详解(三)------垃圾回收
  3. 对scanner.close方法的误解以及无法补救的错误
  4. 18.linux基础优化
  5. 分享几个能用的editplus注册码/2018年序列号
  6. 深入学习Spring框架(四)- 事务管理
  7. Bzoj 3166 [Heoi2013] Alo 题解
  8. STM32F0_HAL库驱动描述——HAL驱动程序概述
  9. Django工程的分层结构
  10. 【题解】Unit Fraction Partition-C++