java - 在无限流上调用 .map()?
问题描述
根据 SE 8 Stream.map() 的 Javadocs,执行以下操作
返回由将给定函数应用于此流的元素的结果组成的流。
但是,我正在阅读的一本关于网络的书(Learning Network Programming with Java,Richard M. Reese)在回显服务器中大致实现了以下代码片段。
Supplier<String> inputLine = () -> {
try {
return br.readLine();
} catch(IOException e) {
e.printStackTrace();
return null;
}
};
Stream.generate(inputLine).map((msg) -> {
System.out.println("Recieved: " + (msg == null ? "end of stream" : msg));
out.println("echo: " + msg);
return msg;
}).allMatch((msg) -> msg != null);
这应该是一种功能性的方式来完成让用户输入打印到套接字输入流。它按预期工作,但我不太明白如何。是不是因为 map 知道流是无限的,所以它会在新的流令牌可用时懒惰地执行?似乎向当前正在被 map 迭代的集合添加一些东西是一个小黑魔法。有人可以帮我了解幕后发生的事情吗?
以下是我如何重述这一点,以避免混淆地图的使用。我相信作者试图避免无限循环,因为您无法摆脱 forEach。
Stream.generate(inputLine).allMatch((msg) -> {
boolean alive = msg != null;
System.out.println("Recieved: " + (alive ? msg : "end of stream"));
out.println("echo: " + msg);
return alive;
});
解决方案
流是懒惰的。将它们想象成链条中的工人,它们将桶相互传递。懒惰在于,如果他们前面的工人向他们要下一个桶,他们只会向他们后面的工人要下一个桶。
因此,最好将其视为allMatch
- 作为最终操作,因此急切 - 向map
流请求下一个项目,map
流向流请求generate
下一个项目,generate
流向其供应商,并尽快提供该项目当它到达时。
当allMatch
停止索取物品时它会停止。当它知道答案时,它就会这样做。此流中的所有项目都不为空吗?一旦allMatch
收到一个为空的项目,它就知道答案是false
,并且将完成并且不再要求任何更多项目。因为流是无限的,否则它不会停止。
所以你有两个因素导致它以它的工作方式工作 - 一个是allMatch
急切地要求下一个项目(只要前一个不为空),以及generate
流 - 为了提供下一个项目 - 可能需要等待等待用户发送更多输入的供应商。
但应该说不map
应该在这里使用。不应该有副作用map
- 它应该用于将一种类型的项目映射到另一种类型的项目。我认为此示例仅用作学习辅助工具。更简单直接的方法是使用BufferedReader
' 方法lines()
Stream
,该方法为您提供来自缓冲阅读器的有限行。
推荐阅读
- sql - 创建一个 SQL 触发器以将多行更改为另一个表?
- flutter - 拒绝从多图像选择器中的存储访问媒体的权限
- reactjs - 如何在 reactjs 中的背景图像上添加文本
- c++ - C++ 中输入的默认值
- python - 如何使用 pandas.plot() 函数绘制具有不同标记的 Pandas 数据框的不同列?
- excel - 从 xlsx 工作表解析数据返回错误数据(Open XML SDK)
- java - 通过 vnet 对等连接将 Azure 应用服务连接到 MongoDB Atlas
- django - Docker:以分离的 -d 模式运行 Celery
- android - Android Listview 和 Dialog 不会显示
- amazon-web-services - 如何使用特定的弹性 IP (EIP) 获取实例的详细信息