注册 | 登录 忘记密码? 51cto首页 | 博客 | 论坛 | 招聘
热点文章 [业内传闻]今天,7月25日..
 帮助

Java:如何处理异常


2008-04-09 14:57:37
 标签:Java 异常   [推送到技术圈]

版权声明:原创作品,如需转载,请与作者联系。否则将追究法律责任。
在处理异常时,应该区分checked异常和unchecked异常。对于checked异常,我们应该提供健壮的异常恢复机制,而对于unchecked异常,这就是编程错误即bug,应该在调试阶段很好的发现和处理它们。
1. Java异常层次结构

上图(注:该图引自http://dev2dev.bea.com.cn/techdoc/200702364792.html)标出了Java异常层次结构,也指出了哪些异常是unchecked,哪些异常是checked。下面给出几段常见的异常处理代理,试图总结日常开发中应该如何处理异常。
2.针对checked异常的恢复机制
checked异常并不是编程错误,它的出现是软件运行阶段所不可避免的。最常见的这类异常如socket连接超时。
对于此类异常,我们应该在程序的运行态下试图从异常中恢复过来。下面这段代码(Recover.java)的主要逻辑是,对目标值protected int current进行判断,如果该值大于2则成功,否则抛出NotBigEnoughException异常。
在执行程序的过程中,在每次catchNotBigEnoughException异常时,我们对current值递增,试图从异常中恢复过来。
NotBigEnoughException.java
package com.zj.exception.types;
 
public class NotBigEnoughException extends Exception {
    public NotBigEnoughException() {
       super();
    }
 
    public NotBigEnoughException(String msg) {
       super(msg);
    }
}
 
Recover.java
package com.zj.exception;
import com.zj.exception.types.NotBigEnoughException;
 
public class Recover {
    protected int current = 0;
    protected boolean accept = false;
 
    public Recover() {}
 
    public Recover(int cur) {
       current = cur;
    }
 
    public void increment() {
       ++current;
    }
 
    public boolean passed() {
       return accept;
    }
 
    public void passing() throws NotBigEnoughException {
       if (current > 2) {
           accept = true;
           System.out.println("accept " + current);
       } else
           throw new NotBigEnoughException("reject " + current);
    }
 
    public static void main(String[] args) {
       Recover re = new Recover();
       while (!re.passed()) {
           try {
              re.passing();
           } catch (NotBigEnoughException e) {
              System.out.println(e);
              re.increment();
           }
       }
    }
}
结果:
com.zj.exception.types.NotBigEnoughException: reject 0
com.zj.exception.types.NotBigEnoughException: reject 1
com.zj.exception.types.NotBigEnoughException: reject 2
accept 3
3.继承异常
在子类继承父类的情况下,子类override方法的异常声明只能取自(小于等于)父类该方法的异常声明;对于子类构造方法的异常声明必须包含(大于等于)父类构造方法的异常声明。
Inheritor继承自类Recover它的方法passing()试图声明一个父类没有的异常UnknowException这样做是不允许的。
UnknowException.java
package com.zj.exception.types;
 
public class UnknowException extends Exception {
    public UnknowException() {
       super();
    }
 
    public UnknowException(String msg) {
       super(msg);
    }
}
error in: Inheritor.java
//couldn't throws new exceptions where not found in its base class
public void passing() throws NotBigEnoughException, UnknowException {
    if (current > 2) {
       accept = true;
       System.out.println("accept " + current);
    } else if (current >= 0)
       throw new NotBigEnoughException("reject " + current);
    else
       throw new UnknowException("i don't know how to deal with "
              + current);
}
之所以覆盖这个方法的目的是对父类的passing()方法做进一步扩展,对0<=current<=2的情况抛出NotBigEnoughException而对current<0的情况则抛出一个新的异常UnknowException
此时,提供两种解决方法。
方法一,使用恢复异常机制,overrding passing()方法,这样可以处理掉所有的异常,因此不需要异常声明。
ok in: Inheritor.java
//sure passing(),so not have to throw exceptions
public void passing(){
    while (!passed()) {
       try {
           super.passing();
       } catch (NotBigEnoughException e) {
           increment();
       }
    }
}
方法二,写一个加强的passing()方法,即fortifiedPassing()对于在父类passing()中捕获的异常,进行再判断。如果是0<=current<=2的情况则重新抛出NotBigEnoughException,如果是current<0的情况则抛出一个新的异常UnknowException
ok in: Inheritor.java
public void fortifiedPassing() throws NotBigEnoughException, UnknowException{
    try {
       super.passing();
    } catch (NotBigEnoughException e) {
       if(current>=0)
           throw e;
       else
           throw new UnknowException("i don't know how to deal with "
                  + current);
    }
}
 
Inheritor.java
package com.zj.exception;
import com.zj.exception.types.NotBigEnoughException;
import com.zj.exception.types.UnknowException;
 
public class Inheritor extends Recover {
    public Inheritor(int cur) {
       super(cur);
    }
 
    //couldn't throws new exceptions where not found in its base class
    /**
    public void passing() throws NotBigEnoughException, UnknowException {
       if (current > 2) {
           accept = true;
           System.out.println("accept " + current);
       } else if (current >= 0)
           throw new NotBigEnoughException("reject " + current);
       else
           throw new UnknowException("i don't know how to deal with "
                  + current);
    }*/
   
    //sure passing(),so not have to throw exceptions
    public void passing(){
       while (!passed()) {
           try {
              super.passing();
           } catch (NotBigEnoughException e) {
              increment();
           }
       }
    }
   
    public void fortifiedPassing() throws NotBigEnoughException, UnknowException{
       try {
           super.passing();
       } catch (NotBigEnoughException e) {
           if(current>=0)
              throw e;
           else
              throw new UnknowException("i don't know how to deal with "
                     + current);
       }
    }
 
    public static void main(String[] args) {
       // not required try-catch
       new Inheritor(3).passing();
       new Inheritor(1).passing();
       new Inheritor(-1).passing();   
       //no exceptions
       try {
           new Inheritor(3).fortifiedPassing();
       } catch (NotBigEnoughException e) {
           e.printStackTrace();
       } catch (UnknowException e) {
           System.out.println(e);
       }
       //NotBigEnoughException:
       try {
           new Inheritor(1).fortifiedPassing();
       } catch (NotBigEnoughException e) {
           e.printStackTrace();
       } catch (UnknowException e) {
           System.out.println(e);
       }
       //UnknownException:
       try {
           new Inheritor(-1).fortifiedPassing();
       } catch (NotBigEnoughException e) {
           e.printStackTrace();
       } catch (UnknowException e) {
           System.out.println(e);
       }
    }
}
结果:
accept 3
accept 3
accept 3
accept 3
com.zj.exception.types.UnknowException: i don't know how to deal with -1
com.zj.exception.types.NotBigEnoughException: reject 1
    at com.zj.exception.Recover.passing(Recover.java:28)
    at com.zj.exception.Inheritor.fortifiedPassing(Inheritor.java:38)
    at com.zj.exception.Inheritor.main(Inheritor.java:63)
4.RuntimeException与包装异常
RuntimeExceptionunhecked异常,它们由JVM抛出(你也可以抛出它),并且不必在异常声明(throws)中列出。
如果RuntimeException没有被catch而到达mian()方法时,那么在程序退出前会自动调用该异常的printStackTrace()方法,打印该异常。
RuntimeException代表的是编程错误(如0除数,数组越界),是应该在调试阶段解决的。
当你在捕获某些异常,而不知道该如果处理时,你可以将它包装为RuntimeException,这样在后续的方法调用过程中就不用声明(throws)该方法了。
在类Wrapper中,我们override fortifiedPassing()方法,并将它可能抛出的异常包装为RuntimeException
Wrapper.java