java.io.InputStreamなどのクラスの関係を図にしてみた


# はじめに

Java SE 7以降はいろいろと有用なクラスが増えて、直接 [java.io][] のクラスを触ることは減っています。ですが、先日久しぶりに [InputStream][] を生で使ったら、使い方が分からなくてググってしまったため、図にしてみました。

使ったことないクラスも多いので、実はこういう使い方もあるよという話がありましたら、コメントお願いします。

# 整理した結果

以下のようになりました。
ただし、これは分かりやすさを重視したもので、正確ではありません。
理由は後述します。

## 読み込み(InputStream, Reader)

![読み込み.png](https://qiita-image-store.s3.amazonaws.com/0/45169/52684498-7b33-57a1-df9e-57cfaed5f611.png)

## 書き込み(OutputStream, Writer)

![書き込み.png](https://qiita-image-store.s3.amazonaws.com/0/45169/ad2ee1b4-aed5-aac3-bc5d-2f163b2db7d4.png)

# 正確に書かなかった理由

いろいろな理由があって、あえて不正確にしています。

## 入れなかったクラス

以下のクラスは外しています。

### 非推奨クラス

- [LineNumberInputStream][]
- [StringBufferInputStream][]

この2つは設計ミスで非推奨になったため、除外しています。

[LineNumberInputStream][]

> このクラスは、文字がバイトによって適切に表現されるという誤った認識を前提としています。

[StringBufferInputStream][]

> このクラスでは、文字からバイトへの変換が正しく行われません。

### フィルタ

- [FilterInputStream][]
- [FilterOutputStream][]

この2つは単独で使用されることがないため、除外しています。何で　abstract　になるように設計しなかったのか?と思ったのですが、同じ疑問を持った人は他にもいるようです。

[java - Why FilterInputStream is not Abstract Class - Stack Overflow](https://stackoverflow.com/questions/21135220/why-filterinputstream-is-not-abstract-class)

自分としては、この [FilterOutputStream][] はそもそもいらないと思います。

### 図に入らなかっただけ

- パイプ関連
  - [PipedInputStream][]
  - [PipedOutputStream][]
  - [PipedReader][]
  - [PipedWriter][]
- [SequenceInputStream][]

これらはしっくり来る位置が見つからなかったので除外しています。
たぶんパイプは独立した図にしたほうがいいと思います。

[SequenceInputStream][] は使ったことないのですが、 [InputStream][] を連結するという特殊なクラスなので、図に入れるとしても隅っこでぼっちになるかなと。

## 継承関係は記載しない

例えば、 [DataInputStream][], [ObjectInputStream][] は [InputStream][] を継承していますが、省いています。 [DataOutputStream][], [ObjectOutputStream][] は [OutputStream][] を継承していますが、省いています。

なぜかというと、これらはそれぞれプリミティブ型、オブジェクトを読み書きするために使うためであって、 [InputStream] として他に渡す場面がなさそうだからです。

これが例えば　[PushbackInputStream][] なら、「先頭の数バイトを読んでファイル形式を自動判別したあと、中身を [InputStream][] として読み込む」といった使い方が想定されます。

あと、 [ObjectInputStream][] は　[InputStream][] を直接継承していますが、 [DataInputStream][] は [FilterInputStream][] を間に挟んでいるのも分かりにくい理由だと思います。同様の疑問を持った人は他にもいるようです。

- [java - Shouldn't ObjectInputStream extend FilterInputStream? - Stack Overflow](https://stackoverflow.com/questions/2896992/shouldnt-objectinputstream-extend-filterinputstream)

## 整理して気づいたこと

### 命名規則が分かりにくい

- 入力元・出力先
- フィルタ
- 加工

これらが全て `XXXInputStream`, `XXXOutputStream`, `XXXReader`, `XXXWriter` という命名規則になっています。そのため区別が付きづらく、混乱の元になっています。

### エンコーディングの扱いがバラバラ

図で背景に色を付けた3つのクラスについては、エンコーディングの扱いが微妙です。

[FileReader][], [FileWriter][] には、エンコーディングを指定するコンストラクタがありません。なので、図には入れましたが、無視した方がいいです。[FileReader][] は遅いという話もありますし、今なら [Files#newBufferedReader][] があります。

- [ファイル読み込みは何がベストなのか（Java） - Qiita](https://qiita.com/motoki1990/items/755c1b0c8d12b49b0c77)

[PrintStream][] は [PrintWriter][] があるので、扱いがよく分かりません。

> PrintWriterクラスは、バイトではなく文字を書き込むことが必要な状況で使用されます。

と書かれていますが、単に [System.out][] と [System.err][] のために残しているのでは?と思います。

# おわりに

図にしてみると、意外とシンプルでした( ´ω`)

あと、リンク貼るのに時間をかけるのはどうかと思いました(´・ω・｀)

[java.io]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/package-summary.html
[Charset#defaultCharset]: https://docs.oracle.com/javase/jp/8/docs/api/java/nio/charset/Charset.html#defaultCharset--
[DataInputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/DataInputStream.html
[DataOutputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/DataOutputStream.html
[Files]: https://docs.oracle.com/javase/jp/8/docs/api/java/nio/file/Files.html
[Files#newBufferedReader]: https://docs.oracle.com/javase/jp/8/docs/api/java/nio/file/Files.html#newBufferedReader-java.nio.file.Path-java.nio.charset.Charset-
[FileReader]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/FileReader.html
[FileWriter]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/FileWriter.html
[FilterInputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/FilterInputStream.html
[FilterOutputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/FilterOutputStream.html
[InputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/InputStream.html
[LineNumberInputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/LineNumberInputStream.html
[ObjectInputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/ObjectInputStream.html
[ObjectOutputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/ObjectOutputStream.html
[OutputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/OutputStream.html
[PipedInputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/PipedInputStream.html
[PipedOutputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/PipedOutputStream.html
[PipedReader]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/PipedReader.html
[PipedWriter]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/PipedWriter.html
[PrintStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/PrintStream.html
[PrintWriter]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/PrintWriter.html
[PushbackInputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/PushbackInputStream.html
[SequenceInputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/SequenceInputStream.html
[StringBufferInputStream]: https://docs.oracle.com/javase/jp/8/docs/api/java/io/StringBufferInputStream.html
[System.err]: https://docs.oracle.com/javase/jp/8/docs/api/java/lang/System.html#err
[System.out]: https://docs.oracle.com/javase/jp/8/docs/api/java/lang/System.html#out