美文网首页
《Thanking in Java》12.异常

《Thanking in Java》12.异常

作者: Lemon_Home | 来源:发表于2017-09-20 22:43 被阅读40次

12.2 基本异常

与使用java中的其他对象一样,我们总是用new在堆上创建异常对象,这也伴随着存储空间的分配和构造器的调用。所有标准异常类都有两个构造器,一个是某认构造器;另一个是接受字符串作为参数,以便能把相关信息放入异常对象的构造器。

能够抛出任意类型的Throwable对象,它是异常类型的根类。

抛出的异常必须在某处得到处理。

虽然恢复模型开始显得很吸引人,但不是很实用。其中的主要原因可能史它所导致的耦合:恢复性的处理程序需要了解异常抛出的地点,这势必要包含依赖与抛出位置的非通用性代码。这增加了代码编写和维护的困难,对于异常可能会从许多地方抛出的大型程序来说,更是如此。

创建自定义异常

创建简单的自定义异常类,可以使用默认构造器和带有字符串的构造器。

//: exceptions/FullConstructors.java

class MyException extends Exception {
  public MyException() {}
  public MyException(String msg) { super(msg); }
}

public class FullConstructors {
  public static void f() throws MyException {
    System.out.println("Throwing MyException from f()");
    throw new MyException();
  }
  public static void g() throws MyException {
    System.out.println("Throwing MyException from g()");
    throw new MyException("Originated in g()");
  }
  public static void main(String[] args) {
    try {
      f();
    } catch(MyException e) {
      e.printStackTrace(System.out);
    }
    try {
      g();
    } catch(MyException e) {
      e.printStackTrace(System.out);
    }
  }
} /* Output:
Throwing MyException from f()
MyException
        at FullConstructors.f(FullConstructors.java:11)
        at FullConstructors.main(FullConstructors.java:19)
Throwing MyException from g()
MyException: Originated in g()
        at FullConstructors.g(FullConstructors.java:15)
        at FullConstructors.main(FullConstructors.java:24)
*///:~

继承结构:MyException -》Exception -》Throwable

12.5 异常说明

异常说明使用了附加的关键子throws,后面接一个所有潜在异常类型的列表。如果方法里的代码产生了异常却没有处理,编译器会发现这个问题并提醒你:要么处理这个异常,要么就在异常说明中表明这个异常。自顶向下强制执行异常说明机制。

12.6 捕获所有异常

捕获异常类型的基类Exception,就能达到捕获所有异常的情况,但是最好将其放在最后。

e.getStackTrace()可以打印出方法调用栈信息。

//: exceptions/WhoCalled.java
// Programmatic access to stack trace information.

public class WhoCalled {
  static void f() {
    // Generate an exception to fill in the stack trace
    try {
      throw new Exception();
    } catch (Exception e) {
      for(StackTraceElement ste : e.getStackTrace())
        System.out.println(ste.getMethodName());
    }
  }
  static void g() { f(); }
  static void h() { g(); }
  public static void main(String[] args) {
    f();
    System.out.println("--------------------------------");
    g();
    System.out.println("--------------------------------");
    h();
  }
} /* Output:
f
main
--------------------------------
f
g
main
--------------------------------
f
g
h
main
*///:~

重抛异常会把异常抛给上一级环境中的异常处理程序,同一个try块的后续catch子句将被忽略。要想更新这个信息,可以调用fillInStackTrace方法。

//: exceptions/Rethrowing.java
// Demonstrating fillInStackTrace()

public class Rethrowing {
  public static void f() throws Exception {
    System.out.println("originating the exception in f()");
    throw new Exception("thrown from f()");
  }
  public static void g() throws Exception {
    try {
      f();
    } catch(Exception e) {
      System.out.println("Inside g(),e.printStackTrace()");
      e.printStackTrace(System.out);
      throw e;
    }
  }
  public static void h() throws Exception {
    try {
      f();
    } catch(Exception e) {
      System.out.println("Inside h(),e.printStackTrace()");
      e.printStackTrace(System.out);
      throw (Exception)e.fillInStackTrace();
    }
  }
  public static void main(String[] args) {
    try {
      g();
    } catch(Exception e) {
      System.out.println("main: printStackTrace()");
      e.printStackTrace(System.out);
    }
    try {
      h();
    } catch(Exception e) {
      System.out.println("main: printStackTrace()");
      e.printStackTrace(System.out);
    }
  }
} /* Output:
originating the exception in f()
Inside g(),e.printStackTrace()
java.lang.Exception: thrown from f()
        at Rethrowing.f(Rethrowing.java:7)
        at Rethrowing.g(Rethrowing.java:11)
        at Rethrowing.main(Rethrowing.java:29)
main: printStackTrace()
java.lang.Exception: thrown from f()
        at Rethrowing.f(Rethrowing.java:7)
        at Rethrowing.g(Rethrowing.java:11)
        at Rethrowing.main(Rethrowing.java:29)
originating the exception in f()
Inside h(),e.printStackTrace()
java.lang.Exception: thrown from f()
        at Rethrowing.f(Rethrowing.java:7)
        at Rethrowing.h(Rethrowing.java:20)
        at Rethrowing.main(Rethrowing.java:35)
main: printStackTrace()
java.lang.Exception: thrown from f()
        at Rethrowing.h(Rethrowing.java:24)
        at Rethrowing.main(Rethrowing.java:35)
*///:~

调用fillInStackTrace就成了异常的新发生地了。

永远不必为清理一个异常对象而担心,或者说为异常对象的清理而担心。它们都是用new在堆上创建的对象,所以垃圾回收器会自动把它们清理掉。

常常会想要在捕获一个异常后抛出另一个异常,并且希望把原始异常的信息保存下来,这被称为异常链。

12.7 java标准异常

Throwable有两种实现类型:Error用来表示编译时和系统错误;Exception可以被抛出的基本类型。

属于运行时异常的类型有很多,它们会自动被java虚拟机抛出,所以不必在异常说明中把它们列出来。如果没有对其进行捕获,那么程序会在退出前将调用异常的printStackTrace方法。

12.8 使用finally进行清理

当java中的异常不允许我们回到异常抛出的地点时,如果把try块方在循环里,就建立了一个“程序继续执行之前必须要达到”的条件。还可以加入一个static类型的计数器或者别的装置,使得循环在放弃以前能尝试一定的次数。这将使程序的健壮性更上一个台阶。

当要把除内存之外的资源恢复到它们的初始状态时,就要用到finally子句。

异常没有被当前的异常处理程序捕获的情况下,异常处理机制也会在跳到更高一层的异常处理程序之前,执行finally子句。

//: exceptions/AlwaysFinally.java
// Finally is always executed.
import static net.mindview.util.Print.*;

class FourException extends Exception {}

public class AlwaysFinally {
  public static void main(String[] args) {
    print("Entering first try block");
    try {
      print("Entering second try block");
      try {
        throw new FourException();
      } finally {
        print("finally in 2nd try block");
      }
    } catch(FourException e) {
      System.out.println(
        "Caught FourException in 1st try block");
    } finally {
      System.out.println("finally in 1st try block");
    }
  }
} /* Output:
Entering first try block
Entering second try block
finally in 2nd try block
Caught FourException in 1st try block
finally in 1st try block
*///:~
//: exceptions/MultipleReturns.java
import static net.mindview.util.Print.*;

public class MultipleReturns {
  public static void f(int i) {
    print("Initialization that requires cleanup");
    try {
      print("Point 1");
      if(i == 1) return;
      print("Point 2");
      if(i == 2) return;
      print("Point 3");
      if(i == 3) return;
      print("End");
      return;
    } finally {
      print("Performing cleanup");
    }
  }
  public static void main(String[] args) {
    for(int i = 1; i <= 4; i++)
      f(i);
  }
} /* Output:
Initialization that requires cleanup
Point 1
Performing cleanup
Initialization that requires cleanup
Point 1
Point 2
Performing cleanup
Initialization that requires cleanup
Point 1
Point 2
Point 3
Performing cleanup
Initialization that requires cleanup
Point 1
Point 2
Point 3
End
Performing cleanup
*///:~

异常丢失,在finally中的方法抛出了另一种异常,则之前的异常信息就会丢失,或者在finally中调用return。解决这个问题需要使用异常链来保存之前抛出的异常。

12.9 异常的限制

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

异常限制对构造器不起作用。派生类构造器不能捕获基类构造器抛出的异常。

异常说明本身并不属于方法类型的一部分,方法类型是由方法的名字与参数的类型组成的。不能基于异常说明来重载方法。

12.10 构造器

对于在构造阶段可能会抛出异常,并且要求清理的类,最安全的使用方式是使用嵌套的try语句:

在创建需要清理的对象之后,立即进入一个try-finally语句块。

12.11 异常匹配

异常处理会按照代码顺序找出最近的处理程序,匹配之后就不再继续查找。查找的时候派生类的对象也可以匹配其基类的处理程序。

12.13 异常使用指南

  1. 在恰当的级别处理问题(在知道该如何处理的情况下才捕获异常。)
  2. 解决问题并且重新调用产生异常的方法。
  3. 进行少许修补,然后绕过异常发生的地方继续执行。
  4. 用别的数据进行计算,意替代方法预计会返回的值。
  5. 把当前运行环境下能做的事情尽量做完,然后把相同的异常重抛到更高层。
  6. 把当前运行环境下能做的事情尽量做完,然后把不同的异常抛到更高层。
  7. 终止程序。
  8. 进行简化(如果你的异常模式使问题变得太复杂,那用起来会非常痛苦也很烦人)
  9. 让类库和程序更安全。

相关文章

  • 《Thanking in Java》12.异常

    12.2 基本异常 与使用java中的其他对象一样,我们总是用new在堆上创建异常对象,这也伴随着存储空间的分配和...

  • 12. Java IO: 异常处理

    想要查看此教程的目录请点击:Java IO教程目录贴地址 Streams或Readers/Writers在使用过程...

  • 《Thanking in Java》9. 接口

    9.1 抽象类和抽象方法 包含抽象方法的类叫做抽象类,如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的。 ...

  • 《Thanking in Java》8. 多态

    多态的作用是消除类型之间的耦合关系。 8.2 转机 除了static方法和final方法(private方法属于f...

  • 《Thanking in Java》16. 数组

    16.1 数组为什么特殊 数组与其他种类的容器之间的区别有三方面:效率、类型和保存基本类型的能力。在java中,数...

  • 《Thanking in Java》20. 注解

    注解,也称为元数据,为我们再代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。...

  • 喜欢

    I love you so gahhhhdamn much" and thanking fans for bein...

  • Java编程思想笔记12.异常处理

    点击进入我的博客 Java异常处理的目的在于通过使用少于目前数量的代码来简化大型、可靠的程序的生成,并且通过这种方...

  • 2018-10-01

    (1) I would like tostart by thanking (2) I’d like to clos...

  • 空指针异常(java.lang.NullPointerExce

    Java空指针异常(java.lang.NullPointerException) Java空指针异常(java....

网友评论

      本文标题:《Thanking in Java》12.异常

      本文链接:https://www.haomeiwen.com/subject/eflssxtx.html