通过异常处理错误

异常处理的优点之一是你可以在某处集中精力处理你要解决的问题,而在另一处处理你编写的这段代码中产生的错误。对于异常情形,在 当前环境下 无法获得必要的信息来解决问题,而是从当前环境跳出,并把问题交给上一级环境。


当抛出异常后,同其他对象的创建一样,使用new在堆上创建异常对象,当前的执行路径被终止,并且从当前环境中弹出对异常对象的引用。此时, 异常处理机制 接管程序,异常处理程序将程序从错误状态中恢复,使程序要么换一种方式执行,要么继续运行。


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


异常处理模型:终止和恢复

终止模型:java支持终止模型,一旦异常被抛出,就表明错误已经无法挽回,也就不能回来继续执行。

恢复模型:通常希望异常被处理之后能继续执行程序。


1. 处理异常机制

异常处理机制:抛出异常、捕获异常


抛出异常:当一个方法出现错误引发异常时。方法创建异常对象并交付运行时系统,异常对象中包含了异常类型和异常出现时的程序状态等异常信息。运行时系统负责寻找处置异常的代码并执行。

throws抛出异常:如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明要抛出的异常类型。throws将异常抛出给调用者后,如果调用者不想处理该异常,可以继续向上抛出但最终要有能够出来了该异常的调用者。



捕获异常:方法抛出异常后,运行时系统转为寻找合适的异常处理器。潜在的异常处理器是异常发生时一次存留在调用栈中的方法集合。运行时系统从发生异常的方法开始,一次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。反之,java程序终止。


2 . 捕获所有的异常

Exception 是与编程有关的所有异常类的基类,不会包含太多具体的信息,不过可以调用它从其基类Throwable继承的方法。

String getMessage() //返回Throwable的详细消息字符串
String getLocalizedMessage() //返回Throwable的本地化描述
String toString() //返回此Throwable的简短描述
void printStackTrace()//将此Throwable及其追踪输出至标准错误流
void pritnStackTrace(PrintStream) //将此Throwable及其追踪输出到指定的输出流
void printStackTrace(java.io.PrintWriter) //将此Throwable及其追踪输出到指定的PrintWriter

1.1 异常链

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


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


3. java 标准异常

Throwable 对象可以分为两种类型:Error用来表示编译时和系统错误,Exception 是可以被抛出的基本类型。


Error:是程序无法处理的错误,表示运行应用程序中较严重的问题。大多数错误与编写者执行的操作无关,而表示代码运行时JVM出现问题。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时。这些错误时不可查的,因为他们在应用程序的控制和处理能力之外。Exception是程序本身可以处理的异常。java的异常(Excdeption和Error)分为可查的异常和不可查的异常。


可查异常(编译器要求必须处置的异常):除RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。它们的特点是JAVA编辑器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。


不可检查的异常。包括运行时异常和错误。


运行时异常会自动被java虚拟机抛出,这些异常都是从RuntimeException类继承而来。 只能在代码中忽略RuntimeException类型的异常,其他类型异常的处理都是由编译器强制实施的。因为RuntimeException 代表的是编程错误。


4.使用finally进行清理

finally字句总能得到执行,它用来将除内存以外的资源恢复到他们的初始状态,需要清理的资源包括:已经打开的文件或网络连接,在屏幕上画的图形等。当在try块或catch中遇到return语句时,finally语句将在方法返回之前被执行。有四种情况,finally不会被执行:


  1. 在finally语句块中发生了异常
  2. 在前面的代码中使用了Systen.exit()退出程序
  3. 程序所在的线程死亡
  4. 关闭CPU

从finally中返回,有可能会导致异常的丢失。


5.异常的限制

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


派生类的构造器不能捕获基类构造器所抛出的异常。当抛出异常时,编译器不会创建对象。不能从异常失败中“恢复”,因为没有基类子对象。

package exception;
//方法被覆盖时,只能抛出在基类方法的异常说明里列出来的那些异常。 
class BaseballException extends Exception {}
class Foul extends BaseballException {}
class Strike extends BaseballException {}

abstract class Inning {
public Inning() throws BaseballException {}
public void event() throws BaseballException {
}
public abstract void atBat() throws Strike, Foul;
public void walk() {} 
}

class StormException extends Exception {}
class RainedOut extends StormException {}
class PopFoul extends Foul {}

interface Storm {
public void event() throws RainedOut;
public void rainHard() throws RainedOut;
}

public class StormyInning extends Inning implements Storm {
//异常限制对构造器不起作用,可以为构造器添加新的异常,但是派生类构造器的异常说明必须包含基类构造器的异常说明
//派生类构造器不能捕获基类构造器抛出的异常
public StormyInning()
 throws RainedOut, BaseballException {}
public StormyInning(String s)
 throws Foul, BaseballException {}
  //基类方法未抛出异常,所以导出类不能抛出异常
 //void walk() throws PopFoul {} //Compile error
//接口不能为现存的来自基类的方法增加异常
//! public void event() throws RainedOut {}
public void rainHard() throws RainedOut {}
//可以不抛出任何异常,即使基类中定义了异常
public void event() {} 
// Overridden methods can throw inherited exceptions:
//重载的方法可以抛出继承的异常
public void atBat() throws PopFoul {}
public static void main(String[] args) {
 try {//仅捕获这个类所抛出的异常
   StormyInning si = new StormyInning();
   si.atBat();
 } catch(PopFoul e) {
   System.out.println("Pop foul");
 } catch(RainedOut e) {
   System.out.println("Rained out");
 } catch(BaseballException e) {
   System.out.println("Generic baseball exception");
 }

 try {
   // 向上转型
   Inning i = new StormyInning();
   i.atBat();
   //必须捕获来自基类方法的异常
 } catch(Strike e) {
   System.out.println("Strike");
 } catch(Foul e) {
   System.out.println("Foul");
 } catch(RainedOut e) {
   System.out.println("Rained out");
 } catch(BaseballException e) {
   System.out.println("Generic baseball exception");
 }
}
} 



6.异常匹配


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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章