Thinking in java系列博文目录:java
本篇文章将讲述关于异常的相关知识程序员
注: 本文首发于 My 公众号 CodeSheep ,可 长按 或 扫描 下面的 当心心 来订阅 ↓ ↓ ↓编程
if( t==null ) throw new NullPointerException(); // 异常对象用new建立于堆上
try { ... } catch( Type1 id1 ) { // 处理Type1类型的异常代码 } catch( Type2 id2 ) { // 处理Type2类型的异常代码 }
建立不带参数ctor的自定义异常类:安全
// 自定义异常类(default ctor) class SimpleException extends Exception {} ------------------------------------------------------------ // 客户端代码 public class UseException { public void fun throws SimpleException { System.out.println( "Throw SimpleExcetion from fun" ); throw new SimpleException(); } public static void main( String[] args ) { UseException user = new UseException(); try { user.fun(); } catch( SimpleException e ) { System.out.println("Caught it !"); } } } ------------------------------------------------------------ // 输出 Throw SimpleExcetion from fun Caught it !
建立带参数ctor的自定义异常类网络
// 自定义异常类(有参ctor) class MyException extends Exception { public MyException() { } public MyException( String msg ) { super(msg); } } ------------------------------------------------------------ // 客户端代码 public class UseException { pubilc static void f() throws MyException { System.out.println( "Throwing MyException from f()" ) throw new MyException(); } public static void g() throws MyException { System.out.println( "Throwing MyException from g()" ) throw new MyException("Originated in g()"); } publib static void main( String[] args ) { try { f(); } catch( MyException e ) { e.printStackTrace( System.out ); } try { g(); } catch( MyException e ) { e.printStackTrace( System.out ); } } } ------------------------------------------------------------ // 输出 Throwing MyException from f() MyException at ... at ... Throwing MyException from g() MyException: Originated in g() // 此即建立异常类型时传入的String参数 at ... at ...
try { ... } catch( Exception e ) { // 填写异常的基类,该catch子句通常置于末尾 ... }
Exception类型所持有的方法:函数
注意:从下往上每一个方法都比前一个提供了更多的异常信息!学习
printStackTrace()方法所提供的栈轨迹信息能够经过getStackTrace()方法来Get,举例:code
try { throw new Exception(); } catch( Exception e ) { for( StackTraceElement ste : e.getStackTrace() ) System.out.println( ste.getMethodName() ); }
这里使用getMethodName()方法来给出异常栈轨迹所通过的方法名!orm
try { ... } catch( Exception e ) { throw e; // 从新抛出一个异常! }
若只是简单地将异常从新抛出,则然后用printStackTrace()显示的将是原异常抛出点的调用栈信息,而非从新抛出点的信息,欲更正该信息,可使用fillInStackTrace()方法:对象
try { ... } catch( Exception e ) { throw (Exception)e.fillInStackTrace(); // 该行就成了异常的新发生地! }
异常链:在捕获一个异常后抛出另外一个异常,并但愿将原始的异常信息保存下来!
解决办法:
注意:Throwable子类中,仅三种基本的异常类提供了待cause参数的ctor(Error、Exception、RuntimeException),其他状况只能靠initCause()方法,举例:
class DynamicFieldsException extends Exception { } public Object setField( String id, Object value ) throws DynamicFieldsException { if( value == null ) { DynamicFieldsException dfe = new DynamicFieldsException(); dfe.initCause( new NullPointerException() ); throw dfe; } Object result = null; try { result = getField(id); } catch( NoSuchFieldException e ) { throw new RuntimeException( e ); } }
try { ... } catch(...) { ... } finally { // finally子句老是会被执行!!! ... }
使用时机:
try { ... } catch(...) { ... } finally { // finally子句老是会被执行!!! sw.off(); // 最后老是须要关掉某个开关! }
public static void func( int i ) { try { if( i==1 ) return; if( i==2 ) return; } finally { print( "Performing cleanup!" ); // 即便上面有不少return,但该句确定被执行 } }
finally存在的缺憾:两种状况下的finally使用会致使异常丢失!
// 异常类 class VeryImportantException extends Exception { poublic String toString() { return "A verfy 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(); // 最后只会该异常生效,lm.f()抛出的异常丢了! } } catch( Exception e ) { System.out.println(e); } } } ----------------------------------------------------------------- // 输出 A trivial exception!
public static void main( String[] args ) { try { throw new RuntimeException(); } finally { return; // 这将会掩盖全部的异常抛出 } }
// 异常类 class A extends Exception { } class A1 extends A { } class A2 extends A { } class A1_1 extends A1 { } class B extends Exception { } class B1 extends B { } ------------------------------------------------- // 用了异常类的基类 abstract class Base { public Base() throws A { } public void event() throws A { } // (1) public abstract void atBat throws A1, A2; public void walk() { } } ------------------------------------------------- // 用了异常类的接口 interface Interf { public void event() throws B1; public void rainHard() throws B1; } ------------------------------------------------- // 继承基类并实现接口的客户端类 public class Ext extends Base implements Interf { public Ext() throws B1, A { } // (2) public Ext( String s ) throws A1, A {} // (2) public void walk() throws A1_1 { } // (3) 编译错误! public void rainHard() throws B1 {} // (4) public void event() { } // (5) public void atBat() throws A1_1 { } // (6) public static void main( String[] args ) { try { Ext ext = new Ext(); ext.atBat(); } catch( A1_1 e ) { ... } catch( B1 e ) { ... } catch( A e ) { ... } try { Base base = new Ext(); ext.atBat(); } catch( A2 e ) { // 这里的catch必须按照Base中函数的异常抛出来写 ... } catch( A1 e ) { ... } catch( B1 e ) { ... } catch( A ) { ... } } }
上面的例子能够总结以下:【注意对应数字标号】
对于在构造阶段可能会抛出异常并要求清理的类,安全的方式是使用嵌套的try子句:即在建立须要清理的对象以后,当即进入一个try-finally块,举例:
特别须要注意的是下面的例子里在ctor中对文件句柄的close应放置的合理位置!
// 须要清理的对象类 class InputFile { private BufferedReader in; InputFile( String fname ) throws Exception { // 构造函数! try { in = new BufferedReader( new FileReader(fname) ); // 这里放置可能抛出异常的其余代码 } catch( FileNotFoundException e ) { // 若上面的FileReader异常,将会抛FileNotFoundException,走到这里,该分支无需in.close()的 System.out.println( "Could not open " + fname ); throw e; } catch( Exception e ) { // 走到这里其实说明in对象已经构建成功,这里是必须in.close()的 try { in.close(); // 注意此处关闭动做单独用try进行保障 } catch( IOException e2 ) { System.out.println("in.close() unsuccessful"); } throw e; } finally { // 注意in.close() 不要在此处关闭,由于try中假如BufferedReader构造失败,此时in对象未生成成功,是无需close()一说的! } } String getLine() { String s; try { s = in.readLine(); } catch( IOException e ) { System.out.println( "readLine() unsuccessful!" ); s = "failed"; } return s; } void cleanup() { // 提供手动的关闭文件句柄的操做函数 try { in.close(); } catch( IOException e ) { System.out.println( "in.close() failed !" ); } } } ---------------------------------------------------- // 客户端代码 public class Cleanup { public static void main( String[] args ) { try { InputFile in = new InputFile( "Cleanup.java" ); try { // 上面InputFile构造完成之后当即进入该try-finally子句! String s = ""; int i = 1; while( (s = in.getLine()) != null ) System.out.println(""+ i++ + ": " + s); } catch( Exception e ) { e.printStackTrace( System.out ); } finally { // 该finally必定确保in能正常cleanup()! in.cleanup(); } } catch( Exception e ) { System.out.println( "InputFile ctor failed!" ); } } // end main() }