Javaでusingブロックもどき(JavaSE7)
Javaのファイナライザ微妙だよな−、という話から発展して、JavaSE7のクロージャでC#のusingブロックのようなものが実現できるようになるかも、という話をしたので、それもついでに補足。
ここで紹介するサンプルは、Closures (Lambda Expressions) for the Java Programming Languageの2008-08-11バージョンで動作確認済み。
【コラム】Java API、使ってますか? (58) Java SE 7の要注目機能"クロージャ"はどうなるのか その6 | 開発・SE | マイナビニュース
を参考に、最大4つのCloseableオブジェクトに対応。
public static <R, T extends Closeable, throws E> R using(T t, { T ==> R throws E } block) throws E, IOException { try { return block.invoke(t); } finally { if (t != null) t.close(); } } public static <R, T1 extends Closeable, T2 extends Closeable, throws E> R using(T1 t1, T2 t2, { T1, T2 ==> R throws E } block) throws E, IOException { try { return block.invoke(t1, t2); } finally { closeAll(t1, t2); } } public static <R, T1 extends Closeable, T2 extends Closeable, T3 extends Closeable, throws E> R using(T1 t1, T2 t2, T3 t3, { T1, T2, T3 ==> R throws E } block) throws E, IOException { try { return block.invoke(t1, t2, t3); } finally { closeAll(t1, t2, t3); } } public static <R, T1 extends Closeable, T2 extends Closeable, T3 extends Closeable, T4 extends Closeable, throws E> R using(T1 t1, T2 t2, T3 t3, T4 t4, { T1, T2, T3, T4 ==> R throws E } block) throws E, IOException { try { return block.invoke(t1, t2, t3, t4); } finally { closeAll(t1, t2, t3, t4); } } private static void closeAll(Closeable...resources) throws IOException { IOException exception = null; for (Closeable resource : resources) { try { if (resource != null) resource.close(); } catch (IOException e) { if (exception == null) exception = e; } } if (exception != null) throw exception; }
クロージャを最後の引数としてとる必要があるため、可変引数が使えないのが難点かな。
closeAllは正直微妙。
使い方はこんな感じ。
using (BufferedReader in, BufferedWriter out : new BufferedReader(new FileReader("Main.java")), new BufferedWriter(new FileWriter("out.txt"))) { String line; while ((line = in.readLine()) != null) { System.out.println(line); out.write(line); out.newLine(); } }
出来ればこんな感じに書きたかった。
using (BufferedReader in : new BufferedReader(new FileReader("Main.java")), BufferedWriter out : new BufferedWriter(new FileWriter("out.txt"))) { // ... }