うおー、久々

なんと、やく半年振りの更新。
ICFPCっぽいことを書こうと思って、でもあんまり練れてないので、
またちょっとしてから出そう(と思っているうちにブームを逃しそうだ。


大学時代の同期他の人と飲んできた。
みんな相変わらずだったけど、ちょっと話題が変わっててなんか年齢を感じたりした。


さて話は変わって、自分メモをかねて会社でちょこちょこ話してたときに出た話題。
よくやるJavaでのファイルとかからデータを読み出す時の処理方法。とりあえず

public class Util {
  public static void close(Closeable c, boolean ignoreException) throws IOException {
    try {
      c.close();
    } catch(IOException e) {
      if (!ignoreException) {
        throw e;
      }
    }
  }
}

みたいのを用意しておきます。で、使い方、

public class Sample {
  public void load(InputStream is) throws IOException {
    // ...実際の処理
  }

  public void loadFromFile(String filename) throws IOException {
    FileInputStream stream = new FileInputStream(filename);
    boolean success = false;
    try {
      load(stream);
      success = true;
    } finally {
      Util.close(stream, !success);
    }
  }
}

コンパイルしてないんで typo とかあるかもです。

  • streamのcloseは一箇所にしたい
  • 読み出しに成功した場合は、closeが失敗した場合IOExceptionを投げて欲しい
  • 読み出しに失敗した場合(i.e. この例だとloadがIOExceptionをthrowした場合)は、closeが失敗しても握りつぶしたい(その上でloadが投げたIOExceptionを呼び出し元に伝播したい)

みたいなのを考えてて、

  • 一箇所にするには finally の中に押し込めるしかない
  • ということは、うまく行ったかどうかを知る方法が必要 → success flag 導入
  • でも、finally のなか大きくなるのやだなぁ → utility 関数導入

みたいな感じでうんうん頭をひねった結果できたのがこんなのです。
あとloadを別関数にしておくと、unittest書きやすい。同じようにsaveも作れる。


booleanがちょっと気に入らないけど、比較的お気に入り。booleanきれいに消せる方法があったらコメントとかで教えてください>誰か。


あと、想定してるのはSampleに直接データを書き込むようなケースですが、
多少の応用はできて、いろんなファイルの種類を読むんだったら、

public abstract class DataReader<T> {
  public abstract T load(...);
  public T loadFromFile(...) { ... }
}

とかにして継承して使うとか(実績なし)。ただ、Fileの代わりにsocketとかでも使いたいことあるよなぁとか考え始めると、たかが読み書きにAPIがだいぶ複雑になるのと、おもちゃ書いてる分にはライブラリにしなくても特に問題ないので、ここまではやってないです。


みたいな tips をいっぱい書こうと思っていた時期があったなぁ、というのをなんとなく思い出したりした。