システム学習Java IO(二)----IO異常処理

2901 ワード

ディレクトリ:システム学習Java IO----ディレクトリ、概要
ストリームを使用すると、StreamsとReaders/Writersを正しく閉じる必要があります.これはclose()メソッドを呼び出すことによって行われます.次のコードを見てください.
InputStream input = new FileInputStream("D:\\out.txt");

int data = input.read();
while(data != -1) {
 //do something with data...
 doSomethingWithData(data);
 data = input.read();
}
input.close();

このコードは一見問題ないようです.しかしdoSomethingWithData()メソッドの内部から異常が放出されるとどうなりますか?そうだ!input.close();は実行の機会が得られず、InputStreamは永遠に閉じません!このような状況を回避するために、ストリームを閉じるコードをfinallyブロックに入れて必ず実行されることを確保し、コードを次のように書き換えることができます.
InputStream input = null;

try{
  input = new FileInputStream("D:\\out.txt");

  int data = input.read();
  while(data != -1) {
      //do something with data...
      doSomethingWithData(data);
      data = input.read();
  }
}catch(IOException e){
  //do something with e... log
} finally {
  if(input != null) input.close();
}

しかしclose()メソッド自体が異常を投げ出すとどうなるのでしょうか.このように流れは閉鎖されますか?このような状況をキャプチャするには、try-catchブロックにclose()の呼び出しを以下に示すように含める必要があります.
} finally {
     try{
       if(input != null) input.close();
     } catch(IOException e){
       //do something, or ignore.
     }
   }

これは確かに問題を解決することができますが、うるさいので見苦しいです.この問題を解決する方法がある.これらの重複コードを抽出して「例外処理テンプレート」と呼ばれる方法を定義します.例外処理テンプレートを作成し、使用後にストリームを正しく閉じます.このテンプレートは一度だけ作成し、コード全体で繰り返し使用しますが、面倒な感じがして、展開しません.
Java 7からtry-with-resourcesという構造を使うことができます
//     try          
try(FileInputStream input = new FileInputStream("file.txt")) {
        int data = input.read();
        while(data != -1){
            System.out.print((char) data);
            data = input.read();
        }   }

tryブロックが完了すると、FileInputStreamは自動的に閉じられます.言い換えれば、スレッドがtryコードブロックを実行している限り、inputstreamは閉じられます.FileInputStreamがJavaインタフェースjavaを実現したからです.lang.AutoCloseable、このインタフェースを実装するすべてのクラスはtry-with-resources構造で使用できます.
public interface AutoCloseable {
   void close() throws Exception;
}

FileInputStreamはこのclose()メソッドを書き換え、ソースコードを表示すると、その下位層がnativeメソッドを呼び出して動作していることがわかります.
try-with-resources構造はJavaの組み込みクラスにのみ適用されません.独自のクラスでjavaを実現することもできる.lang.AutoCloseableインタフェースは、try-with-resources構造などとともに使用されます.
public class MyAutoClosable implements AutoCloseable {
    public void doIt() {
        System.out.println("MyAutoClosable doing it!");
    }
    @Override
    public void close() throws Exception {
        System.out.println("MyAutoClosable closed!");
    }  }
private static void myAutoClosable() throws Exception {
    try(MyAutoClosable myAutoClosable = new MyAutoClosable()){
        myAutoClosable.doIt();
    }
}
//     :
// MyAutoClosable doing it!
// MyAutoClosable closed!

try-with-resourcesは、try-catchブロックで使用されるリソースが自分で作成したものであっても、Javaの組み込みコンポーネントであっても、正しく閉じられるようにする強力な方法です.