熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> JSP教程 >> 正文

Java中的構建器

2013-11-15 11:37:36  來源: JSP教程 

  為違例編寫代碼時我們經常要解決的一個問題是一旦產生違例會正確地進行清除嗎?大多數時候都會非常安全但在構建器中卻是一個大問題構建器將對象置於一個安全的起始狀態但它可能執行一些操作——如打開一個文件除非用戶完成對象的使用並調用一個特殊的清除方法否則那些操作不會得到正確的清除若從一個構建器內部出一個違例這些清除行為也可能不會正確地發生所有這些都意味著在編寫構建器時我們必須特別加以留意
  由於前面剛學了finally所以大家可能認為它是一種合適的方案但事情並沒有這麼簡單因為finally每次都會執行清除代碼——即使我們在清除方法運行之前不想執行清除代碼因此假如真的用finally進行清除必須在構建器正常結束時設置某種形式的標志而且只要設置了標志就不要執行finally塊內的任何東西由於這種做法並不完美(需要將一個地方的代碼同另一個地方的結合起來)所以除非特別需要否則一般不要嘗試在finally中進行這種形式的清除
  在下面這個例子裡我們創建了一個名為InputFile的類它的作用是打開一個文件然後每次讀取它的一行內容(轉換為一個字串)它利用了由Java標准IO庫提供的FileReader以及BufferedReader類(將於第章討論)這兩個類都非常簡單大家現在可以毫無困難地掌握它們的基本用法
  
  //: Cleanupjava
  // Paying attention to exceptions
  // in constructors
  import javaio*;
  
  class InputFile {
   private BufferedReader in;
   InputFile(String fname) throws Exception {
    try {
     in =
      new BufferedReader(
       new FileReader(fname));
     // Other code that might throw exceptions
    } catch(FileNotFoundException e) {
     Systemoutprintln(
      Could not open + fname);
     // Wasnt open so dont close it
     throw e;
    } catch(Exception e) {
     // All other exceptions must close it
     try {
      inclose();
     } catch(IOException e) {
      Systemoutprintln(
       inclose() unsuccessful);
     }
     throw e;
    } finally {
     // Dont close it here!!!
    }
   }
   String getLine() {
    String s;
    try {
     s = inreadLine();
    } catch(IOException e) {
     Systemoutprintln(
      readLine() unsuccessful);
     s = failed;
    }
    return s;
   }
   void cleanup() {
    try {
     inclose();
    } catch(IOException e) {
     Systemoutprintln(
      inclose() unsuccessful);
    }
   }
  }
  
  public class Cleanup {
   public static void main(String[] args) {
    try {
     InputFile in =
      new InputFile(Cleanupjava);
     String s;
     int i = ;
     while((s = ingetLine()) != null)
      Systemoutprintln(+ i++ + : + s);
     incleanup();
    } catch(Exception e) {
     Systemoutprintln(
      Caught in main eprintStackTrace());
     eprintStackTrace();
    }
   }
  } ///:~
  
  該例使用了Java IO類
  用於InputFile的構建器采用了一個String(字串)參數它代表我們想打開的那個文件的名字在一個try塊內部它用該文件名創建了一個FileReader對FileReader來說除非轉移並用它創建一個能夠實際與之交談的BufferedReader否則便沒什麼用處注意InputFile的一個好處就是它同時合並了這兩種行動
  若FileReader構建器不成功就會產生一個FileNotFoundException(文件未找到違例)必須單獨捕獲這個違例——這屬於我們不想關閉文件的一種特殊情況因為文件尚未成功打開其他任何捕獲從句(catch)都必須關閉文件因為文件已在進入那些捕獲從句時打開(當然如果多個方法都能產生一個FileNotFoundException違例就需要稍微用一些技巧此時我們可將不同的情況分隔到數個try塊內)close()方法會擲出一個嘗試過的違例即使它在另一個catch從句的代碼塊內該違例也會得以捕獲——對Java編譯器來說那個catch從句不過是另一對花括號而已執行完本地操作後違例會被重新這樣做是必要的因為這個構建器的執行已經失敗我們不希望調用方法來假設對象已正確創建以及有效
  在這個例子中沒有采用前述的標志技術finally從句顯然不是關閉文件的正確地方因為這可能在每次構建器結束的時候關閉它由於我們希望文件在InputFile對象處於活動狀態時一直保持打開狀態所以這樣做並不恰當
  getLine()方法會返回一個字串其中包含了文件中下一行的內容它調用了readLine()後者可能產生一個違例但那個違例會被捕獲使getLine()不會再產生任何違例對違例來說一項特別的設計問題是決定在這一級完全控制一個違例還是進行部分控制並傳遞相同(或不同)的違例或者只是簡單地傳遞它在適當的時候簡單地傳遞可極大簡化我們的編碼工作getLine()方法會變成
  String getLine() throws IOException {
  return inreadLine();
  }
  但是當然調用者現在需要對可能產生的任何IOException進行控制
  用戶使用完畢InputFile對象後必須調用cleanup()方法以便釋放由BufferedReader以及/或者FileReader占用的系統資源(如文件句柄)——注釋⑥除非InputFile對象使用完畢而且到了需要棄之不用的時候否則不應進行清除大家可能想把這樣的機制置入一個finalize()方法內但正如第章指出的那樣並非總能保證finalize()獲得正確的調用(即便確定它會調用也不知道何時開始)這屬於Java的一項缺陷——除內存清除之外的所有清除都不會自動進行所以必須知會客戶程序員告訴他們有責任用finalize()保證清除工作的正確進行
  
  ⑥在C++裡破壞器可幫我們控制這一局面
  
  在Cleanupjava中我們創建了一個InputFile用它打開用於創建程序的相同的源文件同時一次讀取該文件的一行內容而且添加相應的行號所有違例都會在main()中被捕獲——盡管我們可選擇更大的可靠性
  這個示例也向大家展示了為何在本書的這個地方引入違例的概念違例與Java的編程具有很高的集成度這主要是由於編譯器會強制它們只有知道了如何操作那些違例才可更進一步地掌握編譯器的知識
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19319.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.