北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

複数のStreamと例外

こんなに例外がやっかいだったとは・・・。

ふたつのファイルからデータを読んで、ひとつのファイルに書き込むプログラムを書いてみました。

File in1 = new File("in1.txt");
File in2 = new File("in2.txt");
File out = new File("out.txt");
BufferedReader br1 = null;
BufferedReader br2 = null;
PrintWriter    pw  = null;
try{
    br1 = new BufferedReader(new FileReader(in1));
    br2 = new BufferedReader(new FileReader(in2));
    pw  = new PrintWriter(new FileWriter(out));
    // てけとーに処理
    // ...
}catch(FileNotFoundException e){
    throw new RuntimeException(e);
}catch(IOException e){
    throw new RuntimeException(e);
}finally{
    try{
        if(br1 != null) br1.close();
        if(br2 != null) br2.close();
        if(pw  != null) pw.close();
    }catch(IOException e){
        throw new RuntimeException(e);
    }
}


IBMのページの"必ずしも見た目ほど容易ではない"で書かれてるように、BufferedReader#close()がExceptionで落ちて以下のclose()が呼ばれない可能性があります、と。*1 そこでfinallyの中を変えます。

... 前略 ...
}finally{
    try{
        try{
            if(br1 != null) br1.close();
        }finally{
            try{
                if(br2 != null) br2.close();
            }finally{
                if(pw != null) pw.close();
            }
        }
    }catch(IOException e){
        throw new RuntimeException(e);
    }
}


tryがたくさん出てきて意欲満々な感じのソースですが、あまり好きくありません。ので、以下のように書いてみました。

... 前略 ...
}finally{
    Exception occured = null;
    try{ if(br1 != null) br1.close(); }
    catch(IOException e){ occured = e; }

    try{ if(br2 != null) br2.close(); }
    catch(IOException e){ occured = e; }

    if(pw != null) pw.close();
    if(pw.checkError()) occured = new IOException();

    if(occured != null)
        throw new RuntimeException(occured);
}


こんな感じになりました*2。ネストするよりはマシだと思いますが、どうでしょう?

*1:実際、落ちるもんなんですかねえ?

*2:PrintWriterだけはIOExceptionを投げないのでtry〜catch不要