<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 9.7 構造器 為異常編寫代碼時,我們經常要解決的一個問題是:“一旦產生異常,會正確地進行清除嗎?”大多數時候都會非常安全,但在構造器中卻是一個大問題。構造器將對象置于一個安全的起始狀態,但它可能執行一些操作——如打開一個文件。除非用戶完成對象的使用,并調用一個特殊的清除方法,否則那些操作不會得到正確的清除。若從一個構造器內部“拋”出一個異常,這些清除行為也可能不會正確地發生。所有這些都意味著在編寫構造器時,我們必須特別加以留意。 由于前面剛學了`finally`,所以大家可能認為它是一種合適的方案。但事情并沒有這么簡單,因為`finally`每次都會執行清除代碼——即使我們在清除方法運行之前不想執行清除代碼。因此,假如真的用`finally`進行清除,必須在構造器正常結束時設置某種形式的標志。而且只要設置了標志,就不要執行`finally`塊內的任何東西。由于這種做法并不完美(需要將一個地方的代碼同另一個地方的結合起來),所以除非特別需要,否則一般不要嘗試在`finally`中進行這種形式的清除。 在下面這個例子里,我們創建了一個名為`InputFile`的類。它的作用是打開一個文件,然后每次讀取它的一行內容(轉換為一個字符串)。它利用了由Java標準IO庫提供的`FileReader`以及`BufferedReader`類(將于第10章討論)。這兩個類都非常簡單,大家現在可以毫無困難地掌握它們的基本用法: ``` //: Cleanup.java // Paying attention to exceptions // in constructors import java.io.*; 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) { System.out.println( "Could not open " + fname); // Wasn't open, so don't close it throw e; } catch(Exception e) { // All other exceptions must close it try { in.close(); } catch(IOException e2) { System.out.println( "in.close() unsuccessful"); } throw e; } finally { // Don't close it here!!! } } 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 e2) { System.out.println( "in.close() unsuccessful"); } } } public class Cleanup { public static void main(String[] args) { try { InputFile in = new InputFile("Cleanup.java"); String s; int i = 1; while((s = in.getLine()) != null) System.out.println(""+ i++ + ": " + s); in.cleanup(); } catch(Exception e) { System.out.println( "Caught in main, e.printStackTrace()"); e.printStackTrace(); } } } ///:~ ``` 該例使用了Java 1.1 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 in.readLine(); } ``` 但是當然,調用者現在需要對可能產生的任何`IOException`進行控制。 用戶使用完畢`InputFile`對象后,必須調用`cleanup()`方法,以便釋放由`BufferedReader`以及/或者`FileReader`占用的系統資源(如文件引用)——注釋⑥。除非`InputFile`對象使用完畢,而且到了需要棄之不用的時候,否則不應進行清除。大家可能想把這樣的機制置入一個`finalize()`方法內,但正如第4章指出的那樣,并非總能保證`finalize()`獲得正確的調用(即便確定它會調用,也不知道何時開始)。這屬于Java的一項缺陷——除內存清除之外的所有清除都不會自動進行,所以必須知會客戶程序員,告訴他們有責任用`finalize()`保證清除工作的正確進行。 ⑥:在C++里,“析構器”可幫我們控制這一局面。 在`Cleanup.java`中,我們創建了一個`InputFile`,用它打開用于創建程序的相同的源文件。同時一次讀取該文件的一行內容,而且添加相應的行號。所有異常都會在`main()`中被捕獲——盡管我們可選擇更大的可靠性。 這個示例也向大家展示了為何在本書的這個地方引入異常的概念。異常與Java的編程具有很高的集成度,這主要是由于編譯器會強制它們。只有知道了如何操作那些異常,才可更進一步地掌握編譯器的知識。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看