web-dev-qa-db-ja.com

Javaのnull(Input / Output)Stream APIのユースケースは何ですか?

Java 11では、InputStreamを次のように初期化できます。

_InputStream inputStream = InputStream.nullInputStream();
_

しかし、 _InputStream.nullInputStream_ の潜在的なユースケース、またはOutputStreamの同様のAPI、つまり _OutputStream.nullOutputStream_ を理解できません。

API Javadocsから、それがわかる

reads no bytesという新しいInputStreamを返します。返されるストリームは最初は開いています。 close()メソッドを呼び出すと、ストリームが閉じられます。

close()への後続の呼び出しは効果がありません。ストリームが開いている間、available()read()read(byte[])、... skip(long)、およびtransferTo()メソッドはすべて、ストリームの終わりに到達したかのように動作します。

詳細なリリースノート をさらに詳しく説明しました。

出力を送信するためにターゲットOutputStream/Writerをパラメーターとして必要とするメソッドを使用したいが、他の効果のためにそれらのメソッドをサイレントに実行したい場合があります。

これは、コマンド出力を/ dev/nullにリダイレクトするUnixの機能、またはコマンド出力をNULに追加するDOSの機能に対応します。

しかし、... =と記述されているステートメントのthose methodsが何であるか理解できません。他の効果のためにこれらのメソッドを静かに実行します。 (APIのハンズオンの欠如を非難)

可能であれば、例の助けを借りて、そのような入力または出力ストリームを持つことの有用性を理解するのを誰かが助けてもらえますか?


Edit:さらにブラウジングで見つけることができる同様の実装の1つはApache-commonsです NullInputStream 。テストユースケースをはるかに正当化します。

28
Naman

InputStream型のパラメーターが必要な場合がありますが、データにコードを入力しないことも選択できます。テストでは、おそらくモックを作成する方が簡単ですが、実稼働環境では、コードをifsとフラグで分散させる代わりに、バインドnull入力を選択できます。

比較する:

class ComposableReprinter {
    void reprint(InputStream is) throws IOException {
        System.out.println(is.read());
    }

    void bla() {
        reprint(InputStream.nullInputStream());
    }
}

これとともに:

class ControllableReprinter {
    void reprint(InputStream is, boolean for_real) throws IOException {
        if (for_real) {
            System.out.println(is.read());
        }
    }
    void bla() {
        reprint(new BufferedInputStream(), false);
    }
}

またはこれ:

class NullableReprinter {
    void reprint(InputStream is) throws IOException {
        if (is != null) {
            System.out.println(is.read());
        }
    }
    void bla() {
        reprint(null);
    }
}

出力IMHOの方が理にかなっています。入力はおそらく一貫性のためです。

このアプローチはNull Objectと呼ばれます: https://en.wikipedia.org/wiki/Null_object_pattern

18
Milo Bem

nullでストリーム変数を初期化するよりも安全(1)で表現力豊か(2)の代替手段だと思います。

  1. NPEに関する心配はありません。
  2. [Output|Input]Streamは抽象化です。 null/empty/mockストリームを返すためには、コアの概念から特定の実装まで逸脱する必要がありました。
12
Andrew Tobilko

nullOutputStreamは非常に簡単で明確だと思います:出力を破棄するだけです(> /dev/null)および/またはテスト用(OutputStreamを作成する必要はありません)。

(明らかに基本的な)例:

OutputStream out = ... // an easy way to either print it to System.out or just discard all prints, setting it basically to the nullOutputStream
out.println("yeah... or not");
exporter.exportTo(out); // discard or real export?

nullInputStreamに関しては、おそらく入力ストリームを必要とするAPI(私はモックが好きではありません)や、データを含まない入力ストリームを配信する(現在はより可能性が高い)テスト用です。 nullは実行可能なオプションではありません。

importer.importDocument("name", /* input stream... */);
InputStream inputStream = content.getInputStream(); // better having no data to read, then getting a null

そのインポーターをテストするときは、独自のnullInputStreamを発明する代わりに、またはモックを使用する代わりに、InputStreamを使用できます。ここでのその他の使用例は、APIの回避策または誤用のように見えます;-)

InputStreamの戻りに関して:それはむしろ理にかなっています。データがない場合は、nullInputStreamの代わりにnullを返すと、呼び出し元がnullを処理する必要がなく、次のように読み取ることができます。データがありました。

最後に、これらは別の依存関係を追加せずに私たちの生活を楽にする単なる便利なメソッドです;-)と他の既に述べたように(コメント/回答)、それは基本的に nullオブジェクトパターン の実装です。

null*Streamには、テストをより高速に実行できるという利点もあります。実際のデータをストリームする場合(もちろん、サイズなどに応じて)、テストを不必要に遅くするだけで、すべてのテストを高速で完了させたい場合、正しい? (一部はここにモックを入れます...まあ...)

3
Roland