成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java編程思想學(xué)習(xí)錄(連載之:異常)

pkhope / 622人閱讀

摘要:系列博文目錄編程思想學(xué)習(xí)錄連載之一切都是對象編程思想學(xué)習(xí)錄連載之初始化與清理編程思想學(xué)習(xí)錄連載之內(nèi)部類編程思想學(xué)習(xí)錄連載之異常本篇文章將講述關(guān)于異常的相關(guān)知識注本文首發(fā)于公眾號,可長按或掃描下面的小心心來訂閱基本概念使用異常來提供一致性的錯(cuò)

Thinking in java系列博文目錄:

Java編程思想學(xué)習(xí)錄(連載之:一切都是對象)

Java編程思想學(xué)習(xí)錄(連載之:初始化與清理)

Java編程思想學(xué)習(xí)錄(連載之:內(nèi)部類)

Java編程思想學(xué)習(xí)錄(連載之:異常)

本篇文章將講述關(guān)于異常的相關(guān)知識

注: 本文首發(fā)于 My 公眾號 CodeSheep ,可 長按掃描 下面的 小心心 來訂閱 ↓ ↓ ↓

基本概念

Java使用異常來提供一致性的錯(cuò)誤報(bào)告模型;且可集中錯(cuò)誤處理;且任務(wù)代碼與異常代碼分割開來,易于理解和維護(hù)

雖然異常處理理論有終止模型、恢復(fù)模型兩種,但恢復(fù)模型很難優(yōu)雅地做到,∴并不實(shí)用,實(shí)際中大家都是轉(zhuǎn)向使用終止模型代碼

一個(gè)異常拋出后發(fā)生的兩件事:① 使用new在堆上創(chuàng)建異常對象;② 異常處理機(jī)制開始接管流程(當(dāng)前的執(zhí)行流程被終止)

標(biāo)準(zhǔn)異常類均有兩個(gè)ctor:① default ctor; ② 帶字符串參數(shù)的ctor

Throwable是異常類型的根類

catch異常時(shí),try中拋出的是子類異常,但catch的是基類異常也是OK,但若catch子類異常和基類異常的子句同時(shí)存在時(shí),應(yīng)將基類catch子句放在后面避免“屏蔽”現(xiàn)象發(fā)生

拋出異常 + 捕獲異常

拋出異常(throw):

if( t==null )
  throw new NullPointerException(); // 異常對象用new創(chuàng)建于堆上

捕獲異常(try+catch):

try {
  ...
} catch( Type1 id1 ) { 
  // 處理Type1類型的異常代碼
} catch( Type2 id2 ) {
  // 處理Type2類型的異常代碼
}

雖然上面的id1和id2在處理異常代碼中可能用不到,但不能少,必須定義

異常發(fā)生時(shí),異常機(jī)制搜尋參數(shù)與異常類型相匹配的第一個(gè)catch子句并進(jìn)入

創(chuàng)建自定義異常

創(chuàng)建不帶參數(shù)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 !

創(chuàng)建帶參數(shù)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() // 此即創(chuàng)建異常類型時(shí)傳入的String參數(shù)
      at ...
      at ...
捕獲所有異常
try {
  ...
} catch( Exception e ) { // 填寫異常的基類,該catch子句一般置于末尾
  ...
}

Exception類型所持有的方法:

String getMessage()

String getLocalizedMessage()

String toString()

void printStackTrace()

void printStackTrace( PrintStream )

void printStackTrace( javo.io.PrintWriter )

注意:從下往上每個(gè)方法都比前一個(gè)提供了更多的異常信息!

棧軌跡

printStackTrace()方法所提供的棧軌跡信息可以通過getStackTrace()方法來Get,舉例:

try {
  throw new Exception();
} catch( Exception e ) {
  for( StackTraceElement ste : e.getStackTrace() )
    System.out.println( ste.getMethodName() );
}

這里使用getMethodName()方法來給出異常棧軌跡所經(jīng)過的方法名!

重拋異常
try {
  ...
} catch( Exception e ) {
  throw e;   // 重新拋出一個(gè)異常!
}

若只是簡單地將異常重新拋出,則而后用printStackTrace()顯示的將是原異常拋出點(diǎn)的調(diào)用棧信息,而非重新拋出點(diǎn)的信息,欲更正該信息,可以使用fillInStackTrace()方法:

try {
  ...
} catch( Exception e ) {
  throw (Exception)e.fillInStackTrace(); // 該行就成了異常的新發(fā)生地!
}
異常鏈

異常鏈:在捕獲一個(gè)異常后拋出另一個(gè)異常,并希望將原始的異常信息保存下來!

解決辦法:

在異常的ctor中加入cause參數(shù)

使用initCause()方法

注意:Throwable子類中,僅三種基本的異常類提供了待cause參數(shù)的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 );
  }

}
Java標(biāo)準(zhǔn)異常

看這個(gè)圖需要明確:程序員一般關(guān)心Exception基類型的異常

由圖中可知,Error、RuntimeException都叫做“Unchecked Exception”,即不檢查異常,程序員也無需寫異常處理的代碼,這種自動(dòng)捕獲

若諸如RuntimeException這種Unchecked異常沒有被捕獲而直達(dá)main(),則程序在退出前將自動(dòng)調(diào)用異常的printStackTrace()方法

使用finally進(jìn)行清理
try {
  ...
} catch(...) {
  ...
} finally { // finally子句總是會(huì)被執(zhí)行!?。?  ...
}

使用時(shí)機(jī):

當(dāng)需要把內(nèi)存之外的資源(如:文件句柄、網(wǎng)絡(luò)連接、某個(gè)外部世界的開關(guān))恢復(fù)到初始狀態(tài)時(shí)!

try {
  ...
} catch(...) {
  ...
} finally { // finally子句總是會(huì)被執(zhí)行?。?!
  sw.off(); // 最后總是需要關(guān)掉某個(gè)開關(guān)!
}

在return中使用finally

public static void func( int i ) {
  
  try {
    if( i==1 )
      return;
    if( i==2 )
      return;
  } finally {
    print( "Performing cleanup!" ); // 即使上面有很多return,但該句肯定被執(zhí)行
  }

}

finally存在的缺憾:兩種情況下的finally使用會(huì)導(dǎo)致異常丟失!

前一個(gè)異常還未處理就拋出下一個(gè)異常

// 異常類
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(); // 最后只會(huì)該異常生效,lm.f()拋出的異常丟了!
      }
    } catch( Exception e ) {
      System.out.println(e);
    }
  }
}
-----------------------------------------------------------------
// 輸出
A trivial exception!

finally子句中的return

public static void main( String[] args ) {
  try {
    throw new RuntimeException();
  } finally {
    return; // 這將會(huì)掩蓋所有的異常拋出
  }
}
繼承基類、實(shí)現(xiàn)接口時(shí)的異常限制
// 異常類
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;
}
-------------------------------------------------
// 繼承基類并實(shí)現(xiàn)接口的客戶端類
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) 編譯錯(cuò)誤!
  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中函數(shù)的異常拋出來寫
      ...
    } catch( A1 e ) {
      ...
    } catch( B1 e ) {
      ...
    } catch( A ) {
      ...
    }
    
  }
}

上面的例子可以總結(jié)如下:【注意對應(yīng)數(shù)字標(biāo)號】

(1) 基類的構(gòu)造器或者方法聲明了拋出異常,但實(shí)際上沒有,這里相當(dāng)于為繼承類寫了一個(gè)異常拋出規(guī)范,子類實(shí)現(xiàn)時(shí)安裝這個(gè)規(guī)范來拋異常

(2) 從這兩個(gè)ctor看出:異常限制對ctor不生效,子類ctor可以拋出任何異常而不管基類ctor所拋出的異常

(3) 基類函數(shù)沒拋異常,派生類重寫時(shí)不能瞎拋!

(4) 完全遵守基類的拋出,正常情況

(5) 基類函數(shù)拋了異常,派生類重寫時(shí)不拋也是OK的

(6) 派生類重寫基類函數(shù)時(shí)拋的異常可以是基類函數(shù)拋出異常的子類型

構(gòu)造器中異常如何書寫

對于在構(gòu)造階段可能會(huì)拋出異常并要求清理的類,安全的方式是使用嵌套的try子句:即在創(chuàng)建需要清理的對象之后,立即進(jìn)入一個(gè)try-finally塊,舉例:

特別需要注意的是下面的例子里在ctor中對文件句柄的close應(yīng)放置的合理位置!
// 需要清理的對象類
class InputFile {
  private BufferedReader in;
  
  InputFile( String fname ) throws Exception {  // 構(gòu)造函數(shù)!
    try {
      in = new BufferedReader( new FileReader(fname) );
      // 這里放置可能拋出異常的其他代碼
    } catch( FileNotFoundException e ) { // 若上面的FileReader異常,將會(huì)拋FileNotFoundException,走到這里,該分支無需in.close()的
      System.out.println( "Could not open " + fname );
      throw e;
    } catch( Exception e ) {
      // 走到這里其實(shí)說明in對象已經(jīng)構(gòu)建成功,這里是必須in.close()的
      try {
        in.close();   // 注意此處關(guān)閉動(dòng)作多帶帶用try進(jìn)行保障
      } catch( IOException e2 ) {
        System.out.println("in.close() unsuccessful");
      }
      throw e;
    } finally {
      // 注意in.close() 不要在此處關(guān)閉,因?yàn)閠ry中假如BufferedReader構(gòu)造失敗,此時(shí)in對象未生成成功,是無需close()一說的!
    }
  }

  String getLine() {
    String s;
    try {
      s = in.readLine();
    } catch( IOException e ) {
      System.out.println( "readLine() unsuccessful!" );
      s = "failed";
    }
    return s;
  }

  void cleanup() {  // 提供手動(dòng)的關(guān)閉文件句柄的操作函數(shù)
    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構(gòu)造完成以后立即進(jìn)入該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()
}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/68469.html

相關(guān)文章

  • Java編程思想學(xué)習(xí)連載:內(nèi)部類)

    摘要:非內(nèi)部類通過一個(gè)特殊的鏈接到其外圍類的對象,而類型的內(nèi)部類無此引用。 showImg(https://segmentfault.com/img/remote/1460000012925199); 用thinkpad打字確實(shí)很爽??! Thinking in java系列博文目錄: Java編程思想學(xué)習(xí)錄(連載之:一切都是對象) Java編程思想學(xué)習(xí)錄(連載之:初始化與清理) Java...

    Meils 評論0 收藏0
  • Java編程思想學(xué)習(xí)連載:初始化與清理)

    摘要:注本文首發(fā)于公眾號,可長按或掃描下面的小心心來訂閱關(guān)于構(gòu)造器與初始化無參構(gòu)造器默認(rèn)構(gòu)造器自己未寫編譯器幫忙自動(dòng)創(chuàng)建的若自行定義了構(gòu)造器無論參數(shù)有否,編譯器便停止默認(rèn)創(chuàng)建動(dòng)作類里的對象引用默認(rèn)初始化為,基本類型初始化為構(gòu)造器也是類的靜態(tài)方法四 showImg(https://segmentfault.com/img/remote/1460000015723687); 注: 本文首發(fā)于 ...

    betacat 評論0 收藏0
  • 利用K8S技術(shù)棧打造個(gè)人私有云(連載:私有云客戶端打造)

    摘要:前端技術(shù)棧還是非常龐大的,為了能夠借助已經(jīng)存在的輪子來造出一輛車,所以我選擇了進(jìn)行實(shí)踐。狀態(tài)的管理的狀態(tài)管理依靠完成,用其來管理的所有組件狀態(tài)。私有云客戶端打造主頁面首先是主頁面,可以打開任何一個(gè)云主機(jī)系統(tǒng)的頁面看,基本類似。 showImg(https://segmentfault.com/img/remote/1460000013930354); 【利用K8S技術(shù)棧打造個(gè)人私有...

    Jingbin_ 評論0 收藏0
  • 利用K8S技術(shù)棧打造個(gè)人私有云(連載:私有云客戶端打造)

    摘要:前端技術(shù)棧還是非常龐大的,為了能夠借助已經(jīng)存在的輪子來造出一輛車,所以我選擇了進(jìn)行實(shí)踐。狀態(tài)的管理的狀態(tài)管理依靠完成,用其來管理的所有組件狀態(tài)。私有云客戶端打造主頁面首先是主頁面,可以打開任何一個(gè)云主機(jī)系統(tǒng)的頁面看,基本類似。 showImg(https://segmentfault.com/img/remote/1460000013930354); 【利用K8S技術(shù)棧打造個(gè)人私有...

    shiina 評論0 收藏0
  • 利用K8S技術(shù)棧打造個(gè)人私有云(連載:K8S資源控制)

    摘要:將用戶命令通過接口傳送給,從而進(jìn)行資源的增刪改等操作。要使用編寫應(yīng)用程序,當(dāng)下大多語言都可以很方便地去實(shí)現(xiàn)請求來操作的接口從而控制和查詢資源,但本文主要是利用已有的客戶端來更加優(yōu)雅地實(shí)現(xiàn)的資源控制。 showImg(https://segmentfault.com/img/remote/1460000013517345); 【利用K8S技術(shù)棧打造個(gè)人私有云系列文章目錄】 利用K8S...

    Reducto 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<