Java中null(Input / Output)Stream API的用例是什么?

时间:2018-11-23 14:52:30

标签: java inputstream apache-commons outputstream java-11

使用Java 11,我可以将InputStream初始化为:

InputStream inputStream = InputStream.nullInputStream();

但是我无法理解InputStream.nullInputStreamOutputStream的类似API的潜在用例  即OutputStream.nullOutputStream

从API Javadocs中,我可以弄清楚它

  

返回一个新的InputStream,它不读取任何字节。返回的流是   最初是开放的。通过调用close()方法关闭流。

     

随后对close()的调用无效。流打开时,   available()read()read(byte[]),...   skip(long)transferTo()方法的行为就像流的结尾   已经达到。

我进一步研究了detailed release notes,其中指出:

  

在很多时候我想使用需要的方法   发送输出的目标OutputStream / Writer作为参数,但是   希望静默地执行这些方法以达到其他效果。

     

这对应于Unix中将命令输出重定向到的功能   / dev / null,或在DOS中将命令输出附加到NUL。

但是,我仍然无法理解语句中陈述的那些方法。...为其他效果而静默执行这些方法。 (归咎于我缺乏动手使用API​​)

如果可能的话,有人可以帮助我理解具有这样的输入或输出流的用处吗?


编辑 :我可以在进一步浏览中找到的类似实现之一是apache-commons的NullInputStream,它可以更好地证明测试用例的合理性

3 个答案:

答案 0 :(得分:18)

有时您希望具有InputStream类型的参数,但又希望选择不向代码提供任何数据。在测试中,模拟它可能更容易,但是在生产中,您可以选择绑定空输入,而不是使用if和标志分散代码。

比较:

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);
    }
}

使用输出恕我直言更有意义。输入可能更多是为了保持一致性。

这种方法称为空对象https://en.wikipedia.org/wiki/Null_object_pattern

答案 1 :(得分:12)

与使用null初始化流变量相比,我认为它是一种更安全(1)和更具表达性(2)的选择。

  1. 不用担心NPE。
  2. [Output|Input]Stream是一个抽象。为了返回空/空/模拟流,您必须从核心概念转向特定的实现。

答案 2 :(得分:3)

我认为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 object pattern的实现。

使用null*Stream的好处还在于可以更快地执行测试...如果您流式传输实际数据(当然,取决于大小等),则可能会不必要地减慢测试速度,并且我们都希望测试能快速完成,对吧? (有些人会在这里放模拟……好吧……)