异常

转自:http://blog.csdn.net/touch_2011/article/details/6860043
1、java标准异常概述

Throwable表示任何可以作为异常被抛出的类,有两个子类Error和Exception。从这两个类的源代码中可以看出,这两个类并没有添加新的方法,Throwable提供了所以方法的实现。Error表示编译时和系统错误。Exception是可以被抛出的异常类。RuntimeException继承自Exception(如NullPointerException),表示运行时异常,JVM会自动抛出.
2、自定义异常类

自定义异常类方法: 通过继承Throwable或Exception。异常类的所有实现都是基类Throwable实现的,所以构造自定义异常类完全可以参考Exception和Error类。我们只要添加上自定义异常类的构造方法就可以了

 /** 
     * 自定义异常类方法 
     * 1、通过继承Throwable 
     * 2、通过继承Exception 
     *  
     * @author Touch 
     */  
    public class MyExceptionDemo extends Exception {  

        private static final long serialVersionUID = 1L;  

        public MyExceptionDemo() {  
            super();  
        }  

        public MyExceptionDemo(String message) {  
            super(message);  
        }  

        public MyExceptionDemo(String message, Throwable cause) {  
            super(message, cause);  
        }  

        public MyExceptionDemo(Throwable cause) {  
            super(cause);  
        }  
    }  
    </span>  

3、异常栈及异常处理方式

可以通过try、catch来捕获异常。捕获到的异常。下面的示例演示了几种常用异常处理方式

 import mine.util.exception.MyException;  

    public class ExceptionDemo1 {  
        public void f() throws MyException {  
            throw new MyException("自定义异常");  
        }  

        public void g() throws MyException {  
            f();  
        }  

        public  void h() throws MyException  {  
            try {  
                g();  
            } catch (MyException e) {  
                //1、通过获取栈轨迹中的元素数组来显示异常抛出的轨迹  
                for (StackTraceElement ste : e.getStackTrace())  
                    System.out.println(ste.getMethodName());  
                //2、直接将异常栈信息输出至标准错误流或标准输出流  
                e.printStackTrace();//输出到标准错误流  
                e.printStackTrace(System.err);  
                e.printStackTrace(System.out);  
                //3、将异常信息输出到文件中  
                //e.printStackTrace(new PrintStream("file/exception.txt"));  
                //4、重新抛出异常,如果直接抛出那么栈路径是完整的,如果用fillInStackTrace()  
                //那么将会从这个方法(当前是h()方法)作为异常发生的原点。  
                //throw e;  
                throw (MyException)e.fillInStackTrace();  
            }  
        }  
        public static void main(String[] args) {  
                try {  
                    new ExceptionDemo1().h();  
                } catch (MyException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
        }  
    }  
    </span>  

运行结果:

f
g
h
main
mine.util.exception.MyException: 自定义异常
at demo.others.ExceptionDemo1.f(ExceptionDemo1.java:7)
at demo.others.ExceptionDemo1.g(ExceptionDemo1.java:11)
at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:16)
at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35)
mine.util.exception.MyException: 自定义异常
at demo.others.ExceptionDemo1.f(ExceptionDemo1.java:7)
at demo.others.ExceptionDemo1.g(ExceptionDemo1.java:11)
at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:16)
at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35)
mine.util.exception.MyException: 自定义异常
at demo.others.ExceptionDemo1.f(ExceptionDemo1.java:7)
at demo.others.ExceptionDemo1.g(ExceptionDemo1.java:11)
at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:16)
at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35)
mine.util.exception.MyException: 自定义异常
at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:30)
at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35)

分析上面的程序,首先main函数被调用,然后是调用h函数,再g函数、f函数,f函数抛出异常,并在h函数捕获,这时将依次从栈顶到栈底输出异常栈路径。
4、异常链
这里写图片描述
有时候我们会捕获一个异常后在抛出另一个异常,如下代码所示:

  import java.io.IOException;  

    import mine.util.exception.MyException;  

    public class ExceptionDemo2 {  
        public void f() throws MyException {  
            throw new MyException("自定义异常");  
        }  

        public void g() throws Exception  {  
            try {  
                f();  
            } catch (MyException e) {  
                e.printStackTrace();  
                throw new Exception("重新抛出的异常1");  
            }  
        }  

        public  void h() throws IOException    {  
            try {  
                g();  
            } catch (Exception e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
                throw new IOException("重新抛出异常2");  
            }  
        }  
        public static void main(String[] args) {  
                try {  
                    new ExceptionDemo2().h();  
                } catch (IOException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
        }  
    }  

运行结果:

mine.util.exception.MyException: 自定义异常
at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9)
at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14)
at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23)
at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:32)
java.lang.Exception: 重新抛出的异常1
at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:17)
at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23)
at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:32)
java.io.IOException: 重新抛出异常2
at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:27)
at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:32)

从结果中我们可以看出,异常栈变小了。也就是说丢失了最原始的异常信息。怎样保存最原始的异常信息呢?Throwable类中有个Throwable cause属性,表示原始异常。通过接收cause参数的构造器可以把原始异常传递给新异常,或者通过initCause()方法。如下示例:

 import java.io.IOException;  

    import mine.util.exception.MyException;  

    public class ExceptionDemo2 {  
        public void f() throws MyException {  
            throw new MyException("自定义异常");  
        }  

        public void g() throws Exception  {  
            try {  
                f();  
            } catch (MyException e) {  
                e.printStackTrace();  
                throw new Exception("重新抛出的异常1",e);  
            }  
        }  

        public  void h() throws IOException    {  
            try {  
                g();  
            } catch (Exception e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
                IOException io=new IOException("重新抛出异常2");  
                io.initCause(e);  
                throw io;  
            }  
        }  
        public static void main(String[] args) {  
                try {  
                    new ExceptionDemo2().h();  
                } catch (IOException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
        }  
    } 

结果:

mine.util.exception.MyException: 自定义异常
at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9)
at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14)
at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23)
at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:34)
java.lang.Exception: 重新抛出的异常1
at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:17)
at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23)
at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:34)
Caused by: mine.util.exception.MyException: 自定义异常
at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9)
at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14)
… 2 more
java.io.IOException: 重新抛出异常2
at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:27)
at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:34)
Caused by: java.lang.Exception: 重新抛出的异常1
at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:17)
at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23)
… 1 more
Caused by: mine.util.exception.MyException: 自定义异常
at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9)
at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14)
… 2 more

从结果中看出当获取到“重新抛出异常2的时候,同时可以输出原始异常“重新抛出的异常1“和原始异常”自定义异常,这就是异常链。
5、finally的使用

finally子句总是执行的,通常用来做一些清理工作,如关闭文件,关闭连接等

下面举几个finally的例子:

分析:如果调用in = new BufferedReader(new FileReader(filePath));时发生异常,这时是一个文件路径不存在的异常,也就是说并没有打开文件,这时将会直接跳到catch块,而不会执行try…finally块(并不是finally子句)里面的语句in.close();此时不需要关闭文件。

再看一个例子,会导致异常的丢失

 package demo.others;  

    import mine.util.exception.MyException;  

    public class ExceptionDemo3 {  
        public void f() throws MyException {  
            throw new MyException("异常1");  
        }  

        public void g() throws MyException {  
            throw new MyException("异常2");  
        }  

        public static void main(String[] args) {  

            try {  
                ExceptionDemo3 ex = new ExceptionDemo3();  
                try {  
                    ex.f();  
                } finally {  
                    ex.g();//此时捕获g方法抛出的异常,f方法抛出的异常丢失了  
                }  
            } catch (MyException e) {  
                System.out.println(e);  
            }  

        }  
    }  

结果:mine.util.exception.MyException: 异常2

此时异常1就丢失了
或者这样写:

   package demo.others;  

    import mine.util.exception.MyException;  

    public class ExceptionDemo3 {  

        public void g() throws MyException {  
            throw new MyException("异常2");  
        }  

        public static void main(String[] args) {  
            ExceptionDemo3 ex = new ExceptionDemo3();  
            try {  
                ex.g();  
            } finally {  
                //直接return会丢失所以抛出的异常  
                return;  
            }  

        }  
    }  

6、异常的限制

(1)当覆盖方法时,只能抛出在基类方法的异常说明里列出的那些异常,有些基类的方法声明抛出异常其实并没有抛出异常,这是因为可能在其子类的覆盖方法中会抛出异常

(2)构造器可以抛出任何异常而不必理会基类构造器所抛出的异常,派生类构造器异常说明必须包含基类构造器异常说明,因为构造派生类对象时会调用基类构造器。此外,派生类构造器不能捕获基类构造器抛出的异常。

7、异常的匹配
异常匹配并不要求与抛出的异常完全匹配,也可以匹配该异常的基类。
如果故意把基类异常放在前面,导致子类异常的catch子句永远得不到执行,编译器会报错。

class Annoyance extends Exception {}
class Sneeze extends Annoyance {}
public class Human {
public static void main(String[] args) {
// Catch the exact type:
try {
throw new Sneeze();
} catch(Sneeze s) {
System.out.println("Caught Sneeze");
} catch(Annoyance a) {
System.out.println("Caught Annoyance");
}
// Catch the base type:
try {
throw new Sneeze();
} catch(Annoyance a) {
System.out.println("Caught Annoyance");
}
}
} /* Output:
Caught Sneeze
Caught Annoyance

8、其它可选方式
1、将异常传递给控制台
这里写图片描述
2、用RuntimeException来包装“被检查的异常”。
这里写图片描述

class WrapCheckedException {
      void throwRuntimeException(int type) {
        try {
          switch(type) {
            case 0: throw new FileNotFoundException();
            case 1: throw new IOException();
            case 2: throw new RuntimeException("Where am I?");
            default: return;
          }
        } catch(Exception e) { // Adapt to unchecked:
          throw new RuntimeException(e);
        }
      }
    }


    class SomeOtherException extends Exception {}

    public class TurnOffChecking { private static Test monitor = new Test();
      public static void main(String[] args) {
        WrapCheckedException wce = new WrapCheckedException();
        // You can call f() without a try block, and let
        // RuntimeExceptions go out of the method:
        wce.throwRuntimeException(3);
        // Or you can choose to catch exceptions:
        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);
            }
          }
        monitor.expect(new String[] {
          "FileNotFoundException: " +
          "java.io.FileNotFoundException",
          "IOException: java.io.IOException",
          "Throwable: java.lang.RuntimeException: Where am I?",
          "SomeOtherException: SomeOtherException"
        });
      }
    } ///:~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值