【Java進化史 第5回】NIO.2 ― Fileで戦った俺たちは、なぜ疲れていたのか
Java6までしか知らない50代が、Java7以降をやり直すシリーズ。
今回は Java7で導入された NIO.2(java.nio.file) を扱う。
■ あの頃、ファイル操作は「共通処理」だった
昔、ファイル操作はすべて共通処理にしていた。
ディレクトリ再帰、コピー、削除、存在チェック。
全部、自分たちで書いた。
テストも自分たちでやった。
例外処理も、ログも、バッファサイズも、全部。
正直、たいへんだった。
でも当時は、それが「実力」だと思っていた。
■ Java6以前 ― Fileクラスの世界
▼ 再帰削除(Java6)
public static void deleteDirectory(File dir) {
if (dir.isDirectory()) {
File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
deleteDirectory(file);
}
}
}
dir.delete();
}
- listFiles() が null を返す
- delete() は boolean を返すだけ
- 失敗理由がわからない
- 再帰は自分で書く
だから「共通処理」にした。
そうしないと怖かった。
▼ ファイルコピー(Java6)
public static void copy(File src, File dest) throws IOException {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
in.close();
out.close();
}
- close漏れの恐怖
- 例外時の後処理
- バッファサイズ設計
- テストケースの山
「File操作ユーティリティ」は、どの現場にもあったはずだ。
■ そしてJava7 ― NIO.2の登場
Java7で導入されたのが java.nio.file パッケージ。
通称 NIO.2。
▼ Pathという思想
Path path = Paths.get("sample.txt");
Fileはクラス。
Pathはインターフェース。
ここに設計思想の違いがある。
▼ コピー(Java7)
Files.copy(
Paths.get("a.txt"),
Paths.get("b.txt"),
StandardCopyOption.REPLACE_EXISTING
);
終わり。
共通処理、いらない。
▼ 再帰削除(Java7)
Files.walk(Paths.get("targetDir"))
.sorted(Comparator.reverseOrder())
.forEach(p -> {
try {
Files.delete(p);
} catch (IOException e) {
e.printStackTrace();
}
});
- 再帰を意識しない
- APIが責任を持つ
- 例外が明確
■ NIO.2の「2」の意味
NIO(Java1.4)は Non-blocking IO。
だが NIO.2 の本質は非同期ではない。
File APIの再設計 である。
Fileクラスは拡張性が低く、例外設計も弱く、 シンボリックリンク対応も不十分だった。
だから、作り直した。
■ 思ったこと
あの頃、俺たちはファイル操作を「共通化」していた。
それは技術力の証だと思っていた。
でも違った。
足りなかったのは俺たちじゃない。
足りなかったのはAPIだった。
■ まとめ
| 項目 | Java6以前 | Java7以降 |
|---|---|---|
| 再帰処理 | 自分で実装 | Files.walk |
| コピー | ストリーム手書き | Files.copy |
| 削除 | boolean戻り値 | IOException |
| 設計思想 | クラス中心 | インターフェース中心 |
NIO.2は単なる便利機能ではない。
設計思想の転換点だった。
0 件のコメント:
コメントを投稿