【问题标题】:What is the use case for null(Input/Output)Stream API in Java?Java 中 null(Input/Output)Stream API 的用例是什么?
【发布时间】:2018-11-23 14:52:29
【问题描述】:

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

InputStream inputStream = InputStream.nullInputStream();

但我无法理解 InputStream.nullInputStream 的潜在用例或 OutputStream 的类似 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,它确实更好地证明了测试用例的合理性。

【问题讨论】:

  • 在提出问题时,有时我收到了this question 作为建议查看。那里的链接都没有到达正确的站点,我也没有使用 JDK 工作的经验,可以找到代码行。也许我错过了一些东西,因此在这里链接它。
  • 如何将一个流传递给一个不存在的文件到一个可选的方法。你将如何告诉一个丢弃数据的方法 - 即你如何做> /dev/null。还有 - 测试!
  • 这是null object pattern 的实现。如果您了解模式的含义,您将了解空流的用途。
  • @BoristheSpider 从理论上讲,虽然愿意从流中丢弃数据,但我确实有点理解这意味着什么,但是为什么要这样做(丢弃数据)?是否有任何服务/系统我应该知道知道这样的实现? 测试 - 是的,为此做出贡献也很有意义。
  • @plalx 感谢您的链接。我可以将其与详细的发行说明中关于兼容性问题的讨论相关联,同时进行更改以为 i/o 流创建空安全实现。会进一步阅读并更明智地消化它。再次感谢。

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


【解决方案1】:

有时您希望有一个 InputStream 类型的参数,但也希望能够选择不向您的代码提供任何数据。在测试中,模拟它可能更容易,但在生产中,您可以选择绑定 null input,而不是使用 ifs 和标志分散代码。

比较:

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

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

这种方法称为Null Objecthttps://en.wikipedia.org/wiki/Null_object_pattern

【讨论】:

  • 这绝不是新的或特定于 Java 的。例如,Unix 长期以来一直有/dev/null,它在不同的级别上服务于相同的目的。 Windows 有一个鲜为人知或使用过的NUL 设备,它与此类似(并且来自 DOS)。
【解决方案2】:

我认为它是使用 null 初始化流变量的更安全 (1) 和更具表现力 (2) 的替代方案。

  1. 不用担心 NPE。
  2. [Output|Input]Stream 是一个抽象。为了返回 null/empty/mock 流,您必须从核心概念转向具体实现。

【讨论】:

  • 这就是答案。这与 UNIX 系统上存在 /dev/null 的原因相同 - 因为否则需要对“空”输出进行不同处理。
【解决方案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 并且可以像有数据时那样读取。

最后,这些只是在不添加其他依赖项的情况下让我们的生活更轻松的便捷方法;-) 并且正如其他人已经说过的(cmets/answers),它基本上是null object pattern 的实现。

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

【讨论】:

    猜你喜欢
    • 2017-05-20
    • 1970-01-01
    • 1970-01-01
    • 2016-04-25
    • 2010-09-17
    • 2017-12-04
    • 1970-01-01
    • 2017-02-25
    • 1970-01-01
    相关资源
    最近更新 更多