再学异常

捕获异常异常处理

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值