はじめに
Java SE 7以降はいろいろと有用なクラスが増えて、直接 java.io のクラスを触ることは減っています。ですが、先日久しぶりに InputStream を生で使ったら、使い方が分からなくてググってしまったため、図にしてみました。
使ったことないクラスも多いので、実はこういう使い方もあるよという話がありましたら、コメントお願いします。
整理した結果
以下のようになりました。
ただし、これは分かりやすさを重視したもので、正確ではありません。
理由は後述します。
読み込み(InputStream, Reader)
書き込み(OutputStream, Writer)
正確に書かなかった理由
いろいろな理由があって、あえて不正確にしています。
入れなかったクラス
以下のクラスは外しています。
非推奨クラス
この2つは設計ミスで非推奨になったため、除外しています。
このクラスは、文字がバイトによって適切に表現されるという誤った認識を前提としています。
このクラスでは、文字からバイトへの変換が正しく行われません。
フィルタ
この2つは単独で使用されることがないため、除外しています。何で abstract になるように設計しなかったのか?と思ったのですが、同じ疑問を持った人は他にもいるようです。
java - Why FilterInputStream is not Abstract Class - Stack Overflow
自分としては、この FilterOutputStream はそもそもいらないと思います。
図に入らなかっただけ
これらはしっくり来る位置が見つからなかったので除外しています。
たぶんパイプは独立した図にしたほうがいいと思います。
SequenceInputStream は使ったことないのですが、 InputStream を連結するという特殊なクラスなので、図に入れるとしても隅っこでぼっちになるかなと。
継承関係は記載しない
例えば、 DataInputStream, ObjectInputStream は InputStream を継承していますが、省いています。 DataOutputStream, ObjectOutputStream は OutputStream を継承していますが、省いています。
なぜかというと、これらはそれぞれプリミティブ型、オブジェクトを読み書きするために使うためであって、 InputStream として他に渡す場面がなさそうだからです。
これが例えば PushbackInputStream なら、「先頭の数バイトを読んでファイル形式を自動判別したあと、中身を InputStream として読み込む」といった使い方が想定されます。
あと、 ObjectInputStream は InputStream を直接継承していますが、 DataInputStream は FilterInputStream を間に挟んでいるのも分かりにくい理由だと思います。同様の疑問を持った人は他にもいるようです。
整理して気づいたこと
命名規則が分かりにくい
- 入力元・出力先
- フィルタ
- 加工
これらが全て XXXInputStream
, XXXOutputStream
, XXXReader
, XXXWriter
という命名規則になっています。そのため区別が付きづらく、混乱の元になっています。
エンコーディングの扱いがバラバラ
図で背景に色を付けた3つのクラスについては、エンコーディングの扱いが微妙です。
FileReader, FileWriter には、エンコーディングを指定するコンストラクタがありません。なので、図には入れましたが、無視した方がいいです。FileReader は遅いという話もありますし、今なら Files#newBufferedReader があります。
PrintStream は PrintWriter があるので、扱いがよく分かりません。
PrintWriterクラスは、バイトではなく文字を書き込むことが必要な状況で使用されます。
と書かれていますが、単に System.out と System.err のために残しているのでは?と思います。
おわりに
図にしてみると、意外とシンプルでした( ´ω`)
あと、リンク貼るのに時間をかけるのはどうかと思いました(´・ω・`)