异常

异常情形(exceptional condition)是指阻止当前方法或作用域继续执行的问题。因为在当前环境下无法获得必要的信息来解决问题,你所能做的就是从当前环境跳出,并且把问题提交给上一级环境。

当抛出异常后,首先,Java会使用new在堆上创建异常对象,然后当前的执行路径被终止,并且从当前环境中弹出对异常对象的引用。异常处理机制接管程序并开始在异常处理程序中继续处理程序。

所有标准异常类都有两个构造器:一个是默认构造器,另一个是接受字符串作为参数,以便能把相关信息放入异常对象的构造器。

Throwable霜i 所有异常类型的根类。

监控区域(guarded region)是一段可能产生异常的代码,并且后面跟着处理这些异常的代码。

每个catch子句仅接收一个特殊类型的参数方法。

异常处理程序必须紧跟在try块之后。当异常被抛出时,异常处理机制将负责搜寻参数与异常类型相匹配的第一个处理程序。许多不同的方法调用可能会产生类型相同的异常,只需要提供一个针对此类型的异常处理程序。

异常处理理论上有两种基本类型:终止类型和恢复模型。Java支持终止模型。一旦异常被抛出,就表明错误已无法挽回,也不能回来继续执行。恢复模型是指异常处理的工作是修正错误,然后重新尝试调用处问题的方法,并认为第二次能成功。对于恢复模型,希望异常被处理后能继续执行程序。实现方式通常为把try块放到while循环里,不断进入try块,直到得到满意的结果。

e.printStackTrace()方法将打印“从方法调用处直到异常抛出处”的方法调用序列。默认信息将被输出到标准错误流。

异常说明属于方法声明的一部分,紧跟在形式参数列表之后。异常说明使用了附加关键字throws,后面接一个所有潜在异常类型的列表。

在定义抽象基类和接口时,可以声明方法将抛出异常,但实际上却不抛出。这样派生类或接口实现既能够抛出这些预先声明的异常。

通过捕获异常类型的基类Exception可以捕获所有类型的异常,因此,最好把它放在处理程序列表的最后。

Exception从Throwable继承的方法:

   String getMessage();

   String getLocalizedMessage();

   void printStackTrace();

   void printStrackTrace(PrintStream);

   void printStackTrace(java.io.PrintWriter);

   Throwable fullInStackTrace();//用于在Throwable对象内部记录帧栈的当前状态 

还可以使用String toString();

Exception继承Object的方法:

   getClass();

   getName();

   getSimpleName();

printStackTree()方法所提供的信息可以通过getStackTree()方法来直接访问,这个方法将返回一个由栈轨迹中的元素所构成的数组,其中每一个元素都表示栈中的一帧。元素0时栈顶元素,并且是调用序列中的最后一个方法调用。数组中的最后一个元素个栈底是调用修了中国年的第一个方法调用。

重新抛出异常会把异常抛给上一级环境中的异常处理程序,同一个try块的后续catch子句将不被执行。如果只是把当前异常对象重新抛出,那么printStackTrace()方法显示的将是原来异常抛出的调用栈信息,而非重新抛出点的信息。可以调用fillInStackTrace()方法,它将返回一个Throwable对象,他是通过把当前调用栈信息填入原来那个异常对象而建立的,这样将会显示是一场的新发生地。若在重新捕获一场之后再抛出一个异常,那么调用e.printStackTrace()只会抛出最后一个异常的发生地点。

异常链

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

现在所有Throwable的子类在构造器中都可以接受一个cause对象作为参数,这个cause就用来表示原始异常,这样通过把原始的异常传递给新的异常,使得即使在当前位置创建并抛出了新的异常,也能通过这个异常链追踪到异常最初发生的位置。在Throwable的子类中,只有三中基本的异常类提供了带cause参数的构造器。它们是Error,Exception及RuntimeException。若想把其他类型的异常连接起来,应该使用initCause()方法而不是构造器。

Throwable这个Java类被用来表示任何可以作为异常被抛出的类。Throwable对象可分为两种类型:Error用来表示编译时和系统错误;Exception是可以被抛出的基本类型。

运行时异常会自动被Java虚拟机抛出,都是从RuntimeException类继承而来,被称为不受检查异常。这种异常属于错误,将被自动捕获。对于RuntimeException,编译器不需要异常说明,直接将其输出报告给了System.error。因为如果RuntimeException没有被捕获而到达main()方法,那么在程序退出之前将调用异常的printStackTrace() 方法。

finally

当要把内存之外的资源恢复到它们的初始状态时,就要用到finally子句。这种需要清理的资源包括:已经打开的文件或网络连接,在屏幕上画的图形,甚至可以时外部世界的某个开关。

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

  OK to add new exceptions for constructors,but you must deal with the base constructor exception;

  Regular methods must conform to base class;

  Interface cannot add exceptions to existing method from the base class;

  If the method doesn't already exist in the base class, the exception is ok;

  You can choose not throw any exceptions even if the base version does;

  Overriden methods can throw inherited exceptions;

  

在设计异常时又个问题:应该把异常全部放在这层处理,还是再向上层抛出相同的异常,又或者是不做任何处理直接向上抛出。如果用法恰当的话,直接向上抛出的能简化编程。

对于在构造阶段可能会抛出的异常,并且要求清理的类,最安全的使用方式是使用嵌套的try子句。这种通用的清理惯用法在构造器不抛出任何异常时也应该运用,其基本规则是:在创建需要清理的对象之后,立即进入一个try-finally语句块。

抛出异常的时候,异常处理系统会按照代码的书写顺序找出“最近”的处理程序。找到匹配的处理程序之后,他就认为异常将得到处理,然后就不再继续查找。查找的异常并不要求抛出的异常同处理程序所声明的异常完全匹配。派生类的对象也可以匹配其基类的处理程序。

异常处理的一个重要原则是只有在你知道如何处理的情况下才捕获异常,实际上,异常处理的一个重要目标就是把错误处理的代码同错误发生的地点相分离。

被检查异常会强制你在可能还没准备好处理错误的时候被迫加上catch子句,这就导致了吞食则有害的问题。若通过catch()捕获了异常但并没有进行任何处理或等待以后的处理,虽然通过了编译,但却意识不到异常已经发生。

当在一个普通方法里调用别的方法,要考虑到我不知道怎么处理这个异常,但也不想把它“吞”了,或者打印一些无用的信息。JDK1.4的异常链提供了一种新的思路来解决这个问题。可以直接把“被检查的异常”包装进RuntimeException里面。

try{

}catch(DontKnowHowToDoException e){

  throw new RuntimeException(e);

}

这种技巧给了你一种选择,可以不写try-catch子句和/或异常说明,直接忽略异常,让它自己沿着调用栈往上冒泡。同时,还可以用getCause()捕获并处理特定的异常。

应该在下列情况下使用异常

  在恰当的级别处理问题

  解决问题并且重新调用产生异常的方法

  进行少许修补,然后绕过异常发生的地方继续执行

  用别的数据进行计算,以代替方法预计会返回的值

  把当前运行环境下能做的事情尽量做完,然后把相同的异常重抛到更高层

  把当前运行环境下能做的事情尽量做完,然后把不同的异常抛到更高层

  终止程序

  进行简化

  让类库和程序更加安全

原文地址:https://www.cnblogs.com/forerver-elf/p/6354334.html