简体   繁体   English

Java Stream相当于ReactiveX Observable#scan

[英]Java Stream equivalent of ReactiveX Observable#scan

ReactiveX has this Very Neat operator called Scan , which is like reduce, except it emits each intermediate accumulator. ReactiveX有一个名为Scan的 Very Neat运算符,它类似于reduce,只是它发出每个中间累加器。

How would I accomplish this with Java Streams? 我将如何使用Java Streams完成此任务? Stream#reduce is not what I want because it returns T : Stream#reduce不是我想要的,因为它返回T

T reduce(T identity, BinaryOperator<T> accumulator)

And what I want is to return Stream<T> , with each item of the stream being the T that was returned on each invocation of the accumulator : 我想要的是返回Stream<T> ,流的每个项目都是在每次调用accumulator时返回的T

Stream.of(1, 2, 3)
    .myScan(0, (accumulator, i) -> accumulator + i)
    .collect(Collectors.toList()); // [1, 3, 6]

I could do something lame like reducing a List , then convert back to a Stream , but that's ugly. 我可以做一些la脚的事情,例如减少List ,然后转换回Stream ,但这很丑陋。

Stream does not support this operation. 流不支持此操作。 You could convert it to an iterator, do it there, and convert back to streams, but there is nothing built-in for streams to do this. 您可以将其转换为迭代器,在其中进行处理,然后转换回流,但是流没有内置的功能可以执行此操作。

Try StreamEx . 尝试StreamEx I think it provides the extract API you want: 我认为它提供了所需的数据提取API:

List<Integer> result = StreamEx.of(1, 2, 3).scanLeft((i, j) -> i + j);
System.out.println(result); // [1, 3, 6]

You could try to benefit from otherwise discouraged side-effects . 您可以尝试避免其他不利的副作用 Since your goal is to process the stream and keeping going on with a stream, we can achieve this using the map method. 由于您的目标是处理流并继续进行流处理,因此我们可以使用map方法来实现。 The following code does it utilizing a side-effect. 以下代码利用了副作用。

public class Scan {

  public static void main(String[] args) {
    Accumulator accumulator = new Accumulator();

    Stream<Integer> originalStream = Stream.of(1, 2, 3);
    Stream<Integer> scannedStream = originalStream
      .map(i -> accumulator.accumulate(i));
    List<Integer> list = scannedStream
      .collect(Collectors.toList()); // [1, 3, 6]

    for (Integer i : list) {
      System.out.println(i);
    }
  }

  private static class Accumulator {

    private int value;

    public int accumulate(int i) {
      return value += i;
    }

  }
}

The Accumulator can be replaced by a Function to be used for different scan -operations. Accumulator可以由Function替换,以用于不同的扫描操作。

But you have to be aware of the restrictions and concerns (eg thread-safty). 但是您必须意识到限制和担忧(例如线程安全性)。

The biggest problem of is that is overrated and understood as a magic-bullet solution for everything slightly related to any of Collection. 的最大问题是,它被高估了,并且被认为是与Collection稍有相关的所有事物的魔术子弹解决方案。

This API has been build for the supporting sequential processing of the elements. 构建此API是为了支持元素的顺序处理。 There doesn't exist any Stream-alike method performing the snippet below. 尚无任何类似Stream的方法执行以下代码段。 Moreover, this API is not easily extendable. 而且,此API难以扩展。

Here is what you are speaking about: 这是您正在谈论的内容:

List<Integer> list = new ArrayList<>();
Stream.of(1, 2, 3).reduce(0, (t, u) -> {
    final Integer s = t + u;
    list.add(s);
    return s;
});

System.out.println(list);   // prints [1, 3, 6]

And here is a workaround using AtomicInteger which allows you to continue the streaming after performing the map(..) : 这是使用AtomicInteger一种解决方法,它允许您在执行map(..)之后继续进行流式处理:

AtomicInteger sum = new AtomicInteger(0);
List<Integer> list = Stream.of(1, 2, 3)
    .map(i -> sum.addAndGet(i))
    .collect(Collectors.toList()); 

System.out.println(list);  // prints [1, 3, 6]

Sometimes you have to use different way. 有时您必须使用其他方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM