再学异常

来源:互联网 发布:淘宝没有人工客服了吗 编辑:程序博客网 时间:2024/06/16 03:35

捕获异常异常处理

1.异常处理有两种基本模式:

  • 终止模式:在这种模型中,将假设错误非常关键,以至于程序无法返回到异常发生的地方继续执行,一旦异常被抛出,就表明错误已无法挽回,也不能回来继续执行。(它是Java和c++所支持的模型)
  • 恢复模型:异常处理程序的工作是修正错误,然后重新尝试调用出问题的方法,并认为第二次能成功。

创建自定义异常

1.可以用记录日志来关联异常
代码例子:

class LoggingException extends Exception {    //创建一个Logger对象      private static Logger logger = Logger.getLogger("LoggingException");      public LoggingException() {        //输出字符流        StringWriter trace = new StringWriter();        //将栈跟踪输出到字符流对象        printStackTrace(new PrintWriter(trace));        //使用server日志级别将信息输出到指定对象中        logger.severe(trace.toString());      }    }    public class LoggingExceptions {      public static void main(String[] args) {        try {          throw new LoggingException();        } catch(LoggingException e) {          System.err.println("Caught " + e);        }        try {          throw new LoggingException();        } catch(LoggingException e) {          System.err.println("Caught " + e);        }      }    } 

运行结果:
二月 26, 2015 9:28:23 下午 beyondboy.LoggingException
严重: beyondboy.LoggingException
at beyondboy.LoggingExceptions.main(LoggingExceptions.java:20)

Caught beyondboy.LoggingException
二月 26, 2015 9:28:25 下午 beyondboy.LoggingException
严重: beyondboy.LoggingException
at beyondboy.LoggingExceptions.main(LoggingExceptions.java:25)

Caught beyondboy.LoggingException

捕获所有异常

1.如果只是把当前异常对象重新抛出,那么printStackTrace()方法显示的将是原来异常抛出点的调用栈信息,而并非重新抛出点的信息,要想更新这个信息,可以调用fillInStackTrace()方法,这将返回一个Throwable对象,它是通过把当前调用栈信息填入原来那个异常对象而建立的(也可以通过使用异常对象的initCause()方法来保留原来的异常信息)。
代码例子:

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);        }      }    } 

运行结果:
originating the exception in f()
Inside g(),e.printStackTrace()
java.lang.Exception: thrown from f()
at beyondboy.Rethrowing.f(Rethrowing.java:6)
at beyondboy.Rethrowing.g(Rethrowing.java:10)
at beyondboy.Rethrowing.main(Rethrowing.java:28)
main: printStackTrace()
java.lang.Exception: thrown from f()
at beyondboy.Rethrowing.f(Rethrowing.java:6)
at beyondboy.Rethrowing.g(Rethrowing.java:10)
at beyondboy.Rethrowing.main(Rethrowing.java:28)
originating the exception in f()
Inside h(),e.printStackTrace()
java.lang.Exception: thrown from f()
at beyondboy.Rethrowing.f(Rethrowing.java:6)
at beyondboy.Rethrowing.h(Rethrowing.java:19)
at beyondboy.Rethrowing.main(Rethrowing.java:34)
main: printStackTrace()
java.lang.Exception: thrown from f()
at beyondboy.Rethrowing.h(Rethrowing.java:23)
at beyondboy.Rethrowing.main(Rethrowing.java:34)
2.如果在捕获异常之后抛出另一种异常,有关原来异常发生点的信息会丢失,剩下的是与新的抛出点有关的信息。

class OneException extends Exception {  public OneException(String s) { super(s); }}class TwoException extends Exception {  public TwoException(String s) { super(s); }}public class RethrowNew {  public static void f() throws OneException {    System.out.println("originating the exception in f()");    throw new OneException("thrown from f()");  }  public static void main(String[] args) {    try {      try {        f();      } catch(OneException e) {        System.out.println(          "Caught in inner try, e.printStackTrace()");        e.printStackTrace(System.out);        throw new TwoException("from inner try");      }    } catch(TwoException e) {      System.out.println(        "Caught in outer try, e.printStackTrace()");      e.printStackTrace(System.out);    }  }}

运行结果:
originating the exception in f()
Caught in inner try, e.printStackTrace()
beyondboy.OneException: thrown from f()
at beyondboy.RethrowNew.f(RethrowNew.java:14)
at beyondboy.RethrowNew.main(RethrowNew.java:19)
Caught in outer try, e.printStackTrace()
beyondboy.TwoException: from inner try
at beyondboy.RethrowNew.main(RethrowNew.java:24)

使用finally进行清理

1.当Java中的异常不允许我们回到异常抛出的地点时,那么我们可以把try块放在循坏里,就建立了一个”程序继续执行之前必须要达到”的条件。
代码例子:

class ThreeException extends Exception {}public class FinallyWorks {  static int count = 0;  public static void main(String[] args) {    while(true) {      try {        if(count++ == 0)          throw new ThreeException();        System.out.println("No exception");      } catch(ThreeException e) {        System.out.println("ThreeException");      } finally {        System.out.println("In finally clause");        //跳出while        if(count == 2) break;       }    }  }}

运行结果:
ThreeException
In finally clause
No exception
In finally clause
2.如果finally没有正确使用,容易使异常丢失。
代码例子:

class VeryImportantException extends Exception {      public String toString() {        return "A very important exception!";      }    }    class HoHumException extends Exception {      public String toString() {        return "A trivial exception";      }    }    public class LostMessage {      void f() throws VeryImportantException {        throw new VeryImportantException();      }      void dispose() throws HoHumException {        throw new HoHumException();      }      public static void main(String[] args) {        try {          LostMessage lm = new LostMessage();          try {            lm.f();          } finally {            lm.dispose();          }        } catch(Exception e) {          System.out.println(e);        }      }    }

运行结果:
A trivial exception

异常的限制

1.当覆盖方法的时候,只能抛出在基类方法的异常说明列出的那些异常,派生类构造器的异常说明必须包含基类构造器的异常说明,而不能捕获基类构造器抛出的异常,当派生类覆盖有抛出异常的基类方法时,可以不带有异常说明,但当覆盖没有抛出异常的基类方法时,不可以带有异常说明。
代码例子:

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 {}  //不能改变其基类定义抛出的异常说明//! public void event() throws RainedOut {}  // 这个可以抛出任何异常  public void rainHard() throws RainedOut {}  //不能抛出任何异常  public void event()  {}  //重写可以抛出基类抛出其异常的子类  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");    }  }} 

构造器

1.在关闭物理资源中,由于finally会每次都执行清理代码,如果构造器在其执行过程中半途而废,也许该对象的某些部分还没有被成功创建,而这些部分在finally子句中却要被清理,这样就会产生矛盾,如果构造器有抛出异常,应该在创建需要清理的对象之后,立即进入一个try-finally语句块。
代码例子:

class NeedsCleanup {         //构造器初始出现任何异常      private static long counter = 1;      private final long id = counter++;      public void dispose() {        System.out.println("NeedsCleanup " + id + " disposed");      }    }    class ConstructionException extends Exception {}    class NeedsCleanup2 extends NeedsCleanup {      //构造器初始可能会出现异常的      public NeedsCleanup2() throws ConstructionException {}    }    public class CleanupIdiom {      public static void main(String[] args) {        // 第一种创建一个构造器没有异常对象的清理情况        NeedsCleanup nc1 = new NeedsCleanup();        try {        } finally {          nc1.dispose();        }        // 第二种创建多个构造器没有异常对象的清理情况        NeedsCleanup nc2 = new NeedsCleanup();        NeedsCleanup nc3 = new NeedsCleanup();        try {          // ...        } finally {          nc3.dispose();           nc2.dispose();        }        //第三种创建多个构造器可能会抛出异常对象的清理情况        try {          NeedsCleanup2 nc4 = new NeedsCleanup2();          try {            NeedsCleanup2 nc5 = new NeedsCleanup2();            try {              // ...            } finally {              nc5.dispose();            }          } catch(ConstructionException e) {             System.out.println(e);          } finally {            nc4.dispose();          }        } catch(ConstructionException e) {           System.out.println(e);        }      }    }

运行结果:
NeedsCleanup 1 disposed
NeedsCleanup 3 disposed
NeedsCleanup 2 disposed
NeedsCleanup 5 disposed
NeedsCleanup 4 disposed

异常匹配

1.当处理被检查异常时,编译器可能会强制你在可能还没准备好处理错误的时候被迫加上catch句子,也许就导致了“吞食则有害”的问题,这里可以通过异常链的方法将检查异常转换成不检查的异常。
代码例子:

块处理这不检查的异常        wce.throwRuntimeException(3);        //测试各种异常类型        for(int i = 0; i < 4; i++)          try {            if(i < 3)              wce.throwRuntimeException(i);            else              throw new SomeOtherException();          } catch(SomeOtherException e) {              System.out.println("SomeOtherException: " + 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 am I?
SomeOtherException: beyondboy.SomeOtherException

0 0