最近書いたコード

ストリーム関係の処理をするときはストリームに対する処理を try ブロックで囲って finally で必ずクローズするようにするのが割と定石ですよね?
例えば↓のように。このとき、私はできる限り外側(下記の例では BufferedInputStream)のストリームを閉じるようにしています。

InputStream in = null;
try {
  in = new BufferedInputStream( new FileInputStream( ... ) );
  in.read();// ストリームに対する処理
}
finally {
  if( in!=null ) {
    try {
      in.close();
    }
    catch( IOException ex ) {
      // N/A
      logger.log( Level.WARNING, "ストリームのクローズでIO例外が発生しました。", ex );
    }
  }
}

ところがこれと同じことを ObjectInputStream に対して行なう場合は、ちょっとだけ注意が必要だったりします。
ObjectInputStream は生成直後に元のストリームから数バイト読み込むため、コンストラクタが IOException を送出する可能性があります。このため、以下のようなコードではストリームのクローズ処理が正しく行なわれない可能性あります。

ObjectInputStream in = null;
try {
  in = new ObjectInputStream( new BufferedInputStream( new FileInputStream( ... ) ) );
  Object obj = in.readObject();
}
finally {
  if( in!=null ) {
    try {
      in.close();
    }
    catch( IOException ex ) {
      // N/A
      logger.log( Level.WARNING, "ストリームのクローズでIO例外が発生しました。", ex );
    }
  }
}

もし、ObjectInputStream のコンストラクタで例外が発生した場合、 in 変数は null のままのため、new BufferedInputStream( new FileInputStream( ... ) ) で開かれたストリームは閉じられません。(ObjectOutputStreamを使用したときも同様)

なので、ObjectInputStream のように、コンストラクタが例外を返す可能性のあるストリームを使用する場合、私は以下のように書いています。

InputStream in = null;
try {
  in = new BufferedInputStream( new FileInputStream( ... ) );
  ObjectInputStream objIn = new ObjectInputStream( in );
  in = objIn;

  Object object = objIn.readObject();
}
finally {
  if( in!=null ) {
    try {
      in.close();
    }
    catch( IOException ex ) {
      // N/A
      logger.log( Level.WARNING, "ストリームのクローズでIO例外が発生しました。", ex );
    }
  }
}

変数 in に、段階を経てストリームのオブジェクトを代入することで、たとえ ObjectInputStream のコンストラクタで例外が発生しても、その直前で開かれたストリームは閉じるようにしています。
ちなみに in に objIn を代入しなおしているのは、できる限り外側のストリームを閉じるという自分のポリシーに従ったためです。