今日の役に立たない一言 - Today’s Trifle! -

古い記事ではさまざまなテーマを書いていますが、2007年以降はプログラミング関連の話がほとんどです。

ストリームをクローズするときの例外

ついったーでネタを拾ったのでメモっとく。
Javaでは、ストリームをクローズするためのメソッド close() でも IOException を throw するようになっている。Core APIソースコードを見てないから未確認だけど、たぶん通常の入力ストリームに対して close() を呼び出しても、例外が発生することはないんじゃないかと思う。
でも、出力ストリームの場合には例外が発生する要因がたくさんある。データを出力ストリームに送出後、そのデータが出力先に届く前に close() が呼び出される可能性があるからだ。close() を呼び出したときに IOException が発生した場合は、送出したデータのすべてまたは一部が出力先に届いていないことを意味している。つまり、close()で発生した例外は、通常の write() などで発生した場合と同様に処理すべきだ。例えばユーザがいて、書き込みに失敗したことをユーザに通知する必要があるとき、たとえclose()を呼び出したときに発生した例外でも、ユーザには通知しなければならない。
finally ブロック内に try/catch ブロックを書いて、ストリームをクローズし、その際の例外は無視するコードをときどき見かけるが、これは不適切だ。

    private byte[] data;

    public viod writeTo(OutputStream out) throws IOException {
        try {
           out.write(data);
        } finally {
           try {
               out.close();
           } catch (IOException e) {
               // ignore
           }
        }
    }

close()を呼び出したときに出力ストリームがフラッシュされるとAPIドキュメントにも記載してあるから、フラッシュで例外が発生している可能性がある。その場合、出力先にデータが届いていない可能性がある。つまり、close()を呼び出したときに発生した例外も、呼び元に通知するのが適切だ。

    private byte[] data;

    public viod writeTo(OutputStream out) throws IOException {
        try {
           out.write(data);
        } finally {
           out.close();
        }
    }

MVCアーキテクチャの話にすると、ユーザの操作によってViewからリクエストが発生する。リクエストは、ControllerやModelを経由して、何らかのデータがストリームで処理される。そこで発生した例外は、最終的にViewまで通知して、ユーザがどうすべきかを判断できるようなメッセージを出力しなければならない。だから、ModelとControllerで、ストリームにアクセスするまでに経由するメソッドは、すべて throws IOException と宣言するのが適切である。
ところで、close()を呼び出したときに例外が発生した場合でも、ストリームはきちんとクローズ(ストリーム関連のリソースを解放)されているんだろうか?たぶん、されてるんだろうな。