彻底明白JAVA的异常处理-2

2.         异常规格(exception specification

1)        在函数定义时可以声明异常规格。如果一个函数在异常规格中声明了non-RuntimeException异常,那么当调用这个函数时,就一定要捕捉异常规格中的non-RuntimeException异常。

import java.lang.RuntimeException;

import java.lang.NullPointerException;

import java.sql.SQLException;

class TestException{

       //1)异常规格中声明将抛出RuntimeException异常

public void testRuntime() throws RuntimeException {}

//2)异常规格中声明将抛出NullPointerException异常

public void testNullPointer() throws NullPointerException {}

//3)异常规格中声明将抛出non-RuntimeException异常

    public void testNonRuntime() throws SQLException {}

}

public class Test{  

    public static void main(String[] args){

        TestException te = new TestException();

        te.testRuntime(); //4

        te.testNullPointer(); //5

        //te.testNonRuntime(); 6

        try{

            te.testNonRuntime();

        }

        catch(SQLException ex){}

    }

}

在上述代码中,(1)处在异常规格中声明将抛出RuntimeException;(2)在异常规格中声明将抛出NullPointerException,而NullPointerExceptionRuntimeException的子类,所以在调用这两个函数时,可不捕捉异常,如(4)(5)处的代码一样直接调用。但(3)处在异常规格中声明将抛出SQLException,而SQLException不是RuntimeException的子类,所以必须捕捉SQLException异常。

2)        如果要在一个函数中抛出non-RuntimeException异常,则必须要在异常规格中声明该异常。

import java.sql.SQLException;

import java.io.IOException;

class Test1{

    public void f() throws SQLException{ //2

       throw new IOException("IOException");  //1

    }

}

public class ExplicitStatic{  

    public static void main(String[] args){

        Test1 te = new Test1();

        try{

            te.f();

        }

        catch(Exception ex){

            System.out.println("catch Exception in main");

        }

    }

}

在(1)处抛出了一个没有在异常规格中被声明的non-RuntimeException异常,在编译时会出错。

2.         取得异常中的信息的几个函数

1)        String getMessage()getLocalizedMessage toString

取得异常对象中的信息

              import java.lang.RuntimeException;

import java.lang.NullPointerException;

Import java.sql.SQLException;

import java.io.IOException;

class TestException{

                  public void tSql() throws SQLException {

                      System.out.println("Originating the exception in tSql()");

                      throw new SQLException("throw in tSql");

                  }

}

public class Test{  

                  public static void main(String[] args){

                      TestException te = new TestException();

                      try{

                          te.tSql();

                      }

                      catch(SQLException ex){

                          System.out.println("catch SQLException in main");

                          System.out.println("ex.getMessage()" + ex.getMessage());

System.out.println("ex.getLocalizedMessage()" +

ex.getLocalizedMessage());

                          System.out.println("ex.toString()" + ex.toString());

                      }

                      catch(Exception ex){

                          System.out.println("catch Exception in main");

                      }

                  }

}

       运行结果:

       Originating the exception in tSql()

catch SQLException in main

ex.getMessage()throw in tSql

ex.getLocalizedMessage()throw in tSql

ex.toString()java.sql.SQLException: throw in tSql

2)        void printStackTrace()Throwable fillStackTrace()

printStackTrace打印出Throwable和其call stack trace

FillStackTrace则在调用点设立新的stack trace信息

import java.sql.SQLException;

class TestException{

    public static void tSql() throws SQLException {

        System.out.println("Originating the exception in tSql()");

        throw new SQLException("throw in tSql");

    }

    public void f() throws SQLException{

        try{

            tSql();

        }

        catch(SQLException ex){

            System.out.println("In f(), e.printStackTrace()");

            ex.printStackTrace();

throw ex; //1

//throw (SQLException)ex.fillInStackTrace(); 2

        }

    }

}

public class Test{  

    public static void main(String[] args){

        TestException te = new TestException();

        try{

            te.f();

        }

        catch(SQLException ex){

            System.out.println("catch in main, e.printStackTrace()");

            ex.printStackTrace();

        }

        catch(Exception ex){

            System.out.println("catch Exception in main");

        }

    }

}

结果为:

Originating the exception in tSql()

In f(), e.printStackTrace()

catch in main, e.printStackTrace()

java.sql.SQLException: throw in tSql

       void TestException.tSql()

              Test.java:5

       void TestException.f()

              Test.java:9

       void Test.main(java.lang.String[])

              Test.java:22

java.sql.SQLException: throw in tSql

       void TestException.tSql()

              Test.java:5

       void TestException.f()

              Test.java:9

       void Test.main(java.lang.String[])

              Test.java:22

                     如果把(1)处代码注释掉,并去年(2)处代码的注释,结果将变成:

Originating the exception in tSql()

In f(), e.printStackTrace()

catch in main, e.printStackTrace()

java.sql.SQLException: throw in tSql

       void TestException.tSql() //3

              Test.java:6

       void TestException.f()

              Test.java:10

       void Test.main(java.lang.String[])

              Test.java:24

java.sql.SQLException: throw in tSql

       void TestException.f() //4

              Test.java:16

       void Test.main(java.lang.String[])

              Test.java:24

由于在代码(2)处设立新的stack trace信息,所以异常会被认为是在f()中发出的,所以在main()中得到的异常原始抛出点为f()(见(3)),而在f()中为tSql()(见(6))。

3)        如果重新抛出一个不同类型的异常,也能产生fillStackTrace()函数的效果。如果把上面代码的f()函数修改成下面的样子:

public void f() throws SQLException,IOException{

try{

        tSql();

    }

    catch(SQLException ex){

        System.out.println("In f(), e.printStackTrace()");

        ex.printStackTrace();      

        throw new IOException(); //1

    }

}

则结果为:

Originating the exception in tSql()

In f(), e.printStackTrace()

catch Exception in main

java.sql.SQLException: throw in tSql

       void TestException.tSql()

              Test.java:6

       void TestException.f()

              Test.java:10

       void Test.main(java.lang.String[])

              Test.java:25

java.io.IOException

       void TestException.f()

              Test.java:17

       void Test.main(java.lang.String[])

              Test.java:25

由于在(1)处抛出了一个新的类型的异常,那么在main()中捕捉到的是新的异常,所以在main()中捕捉到的异常的原始抛出点为f()

3.         RuntimeException异常

RuntimeException及其子类所代表的异常我们在程序中不用进行捕捉,如果发生此类异常,Java会自动抛出相应的异常对象,如:

class TestException{   

    public static void g(int x) {

        System.out.println("10/" + x + " = " + 10/x);

    }

}

public class Test{  

    public static void main(String[] args){

        TestException.g(2);

        TestException.g(0); //1

    }

}

上面代码在编译时不会发生错误,只有在运行时(1)处会发生错误。虽然除法可能会存在错误,但我们不用进行捕捉,当发生错误时,Java会自动抛出相应异常。

二.finally进行清理

1.         如果某段代码不管是否发生异常都要执行,那可把它改入finally块中。

import java.sql.SQLException;

class TestException{

    public static void tSql() throws SQLException {

        System.out.println("Originating the exception in tSql()");

        throw new SQLException("throw in tSql");

    }

    public void f() throws SQLException{

        try{

            tSql();

        }

        catch(SQLException ex){

            System.out.println("catch SQLException in f()");

            throw ex; //1

        } 

        finally{

            System.out.println("finally in f()");

        }

    }

}

public class Test{  

    public static void main(String[] args){

        TestException te = new TestException();

        try{

            te.f();

        }

        catch(SQLException ex){

            System.out.println("catch te.f() SQLException in main");

        }

        catch(Exception ex){

            System.out.println("catch te.f() Exception in main");

        }

    }

}

运行结果为:

Originating the exception in tSql()

catch SQLException in f()

finally in f()

catch te.f() SQLException in main

虽然在代码(1)处重新抛出异常,但finally块中的代码仍然会被执行。

2.         finally造成的异常遗失

如果在finally中执行的代码又产生异常,那么在上一层调用中所捕捉到的异常的起始抛出点会是finally所在的函数。

import java.sql.SQLException;

class TestException{

    public static void tSql1() throws SQLException {

        System.out.println("Originating the exception in tSql()");

        throw new SQLException("throw in tSql1");

    }

    public static void tSql2() throws SQLException {

        System.out.println("Originating the exception in tSql()");

        throw new SQLException("throw in tSql2");

    }

    public void f() throws SQLException{

        try{

            tSql1();

        }

        catch(SQLException ex){

            System.out.println("catch SQLException in f()");

            throw ex; //2

        } 

        finally{

            System.out.println("finally in f()");

            //tSql2(); (1

        }

    }

}

public class Test{  

    public static void main(String[] args){

        TestException te = new TestException();

        try{

            te.f();

        }

        catch(SQLException ex){

            System.out.println("catch te.f() SQLException in main");

            System.out.println("getMessage" + ex.getMessage());

            System.out.println("printStackTrace");

            ex.printStackTrace();

        }

    }

}

运行结果为:

Originating the exception in tSql()

catch SQLException in f()

finally in f()

catch te.f() SQLException in main

getMessagethrow in tSql1

printStackTrace

java.sql.SQLException: throw in tSql1

       void TestException.tSql1()

              Test.java:5

       void TestException.f()

              Test.java:13

       void Test.main(java.lang.String[])

              Test.java:29

从结果可以看出,在main()中能正确打印出所捕捉到的异常的起始抛出点。但如果去掉代码(1)的注释,结果将变为:

Originating the exception in tSql()

catch SQLException in f()

finally in f()

Originating the exception in tSql()

catch te.f() SQLException in main

getMessagethrow in tSql2

printStackTrace

java.sql.SQLException: throw in tSql2

       void TestException.tSql2()

              Test.java:9

       void TestException.f()

              Test.java:21

       void Test.main(java.lang.String[])

              Test.java:29

从结果可以看出,在main()中捕捉到的异常是finally中产生的异常,代码(2)中抛出的异常丢失了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值