【问题标题】:How to terminate a Java stream without the use of a terminating statement?如何在不使用终止语句的情况下终止 Java 流?
【发布时间】:2021-04-21 14:08:40
【问题描述】:

我一直在玩流,然后我注意到当我执行以下操作时,它不会在控制台中产生输出:

String[] is = {"Hello", "World", "My", "Name", "Is", "Jacky"};
Arrays.stream(is).peek(s -> System.out.println(s));

我认为这是因为peek() 是一种非终止流方法,应该使用forEach() 而不是peek() 来终止流并产生结果:

Arrays.stream(is).forEach(s -> System.out.println(s));

但是,有没有一种方法可以“提前”终止流,可能使用自定义终止方法(功能接口),除了终止流之外什么都不做?.. 有没有合适的方法来做到这一点是否已经存在于 Java 中?

我知道我可以这样做:

Arrays.stream(is).peek(s -> System.out.println(s)).forEach(s -> {});

但这感觉很浪费。

【问题讨论】:

  • @DanielZ。我猜 OP 的问题是是否有无操作终止语句。我对 Java 1.8 以外的知识非常有限。至少对于 Java 1.8,答案似乎是“否”:没有 sink()/consume()/terminate() 操作。写一个显然是微不足道的(正如 OP 所示);但什么是“最不浪费”的方式(forEach(s -> {}) 实际上似乎是一个不错的选择)?
  • @KonradRudolph 没有这样的事情。对 OP 来说更糟糕的是,理论上,forEach(s -> {}) 可以被编译器完全解除(它毕竟什么都不做),因此任何其他中间操作也是如此,有效地使这个流成为 NO-OP。
  • 从角度来看,如果您发现自己处于需要无操作终端操作的位置,那么根据 java,您不需要以流开头...
  • 不能forEach之后使用collect
  • 原则上,如果forEach被一个可证明忽略其输入的函数调用,即使该函数确实做了一些事情,也可以允许实现不消耗流的元素,例如x -> System.out.println("Hello")。理论上,这可以通过使用 null 输入调用函数 .count() 次来实现,并且将难以编写正式保证消费流的 any 无操作终端操作。跨度>

标签: java java-stream


【解决方案1】:

没有这样的东西。

已经围绕此类功能进行了讨论,例如here,您可以在其中了解到这不会发生以及原因。

您最好的选择是forEach(x -> {}),或者您可以自己创建这样一个虚拟消费者并在任何需要的地方使用它:

static class Dummies {
     static <T> Consumer<T> getConsumer() {
         return x -> {};
     }
}

【讨论】:

  • 我不确定链接的讨论是否与 OP 的意图有关。相反,当使用可识别的无操作消费者时,可能会导致 not 处理元素的优化。 OP 的实际问题的一般答案应该是不要尝试在中间操作中强制执行副作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-31
  • 1970-01-01
  • 2022-08-15
相关资源
最近更新 更多