简体   繁体   English

Java 8 Stream实用程序用于输入数据

[英]Java 8 Stream utilities for input data

Imagine having some sort of incoming data either by callback or an InputStream that you need to continuously convert into a Java 8 Stream . 想象一下,通过回调或InputStream拥有某种传入数据,您需要将它们连续转换为Java 8 Stream We don't know when the incoming data-stream stops, but we know that it can stop. 我们不知道传入的数据流何时停止,但我们知道它可以停止。

So far I've seen two ways of getting around this problem and I'm interested in the best practices on how to achieve this. 到目前为止,我已经看到了解决此问题的两种方法,并且我对实现此问题的最佳实践感兴趣。 Mainly because I this must be something someone has faced before. 主要是因为我这一定是某人以前遇到过的事情。 There must be a simpler way of doing it than the ideas below. 必须有比下面的想法更简单的方法。

1) The most simple way is to treat the source as a Supplier and just use Stream.generate to serve data: 1)最简单的方法是将源视为Supplier而仅使用Stream.generate来提供数据:

Stream.generate(() -> blockCallToGetData());

However, this has the disadvantage, that the stream never ends. 但是,这样做的缺点是流永远不会结束。 So whenever an input source stops sending, the stream just keeps calling the method. 因此,只要输入源停止发送,流就只会继续调用该方法。 Unless we throw a Runtime exception naturally, but this can get ugly fast. 除非我们自然抛出一个Runtime异常,否则这很快就会变得丑陋。

2) The second idea is to use a Iterator (converted to a Spliterator ) where the next method blocks until we find the next element. 2)第二个想法是使用Iterator (转换为Spliterator ),其中next方法将阻塞,直到找到下一个元素为止。 As a crude example: 作为一个粗略的例子:

class BlockingIterator implements Iterator<Data> {

  @Override void boolean hasNext() {
    return true;
  }

  @Override Data next() {
    return blockCallToGetData();
  }

}

The advantage of this is that I can stop the stream by returning false in the hasNext method. 这样做的好处是,我可以通过在hasNext方法中返回false来停止流。 However, in situations where we do not control the speed of the incoming data (such as in a callback), we would need to keep a buffer of ready elements for the iterator. 但是,在无法控制传入数据速度的情况下(例如在回调中),我们需要为迭代器保留一个ready元素的缓冲区。 This buffer could grow infinitely big, before someone calls next on the iterator. 在有人在迭代器上调用next之前,此缓冲区可能会无限增大。

So, my question goes; 所以,我的问题是; what is the best practice for serving blocking input into a stream? 阻止流中输入的最佳做法是什么?

The question contains a questionable assumption: that there is a good practice for serving blocking input into a stream. 这个问题包含了一个可疑的假设: 在职阻断输入到一个流一个很好的做法。 Stream is not a reactive framework; 流不是一个被动框架。 while you can wedge it into being one with a big crowbar, the problems will likely pop out elsewhere as a result. 虽然您可以将它楔入一个大撬棍中,但结果很可能会在其他地方弹出问题。 (The EG considered these use cases and concluded that we were better off providing something that does a complete job at one problem rather than a half job at two.) (专家组考虑了这些用例,并得出结论,我们最好提供在一个问题上能完成全部任务的东西,而不是在两个问题上只完成一半的事情。)

If you need a reactive framework, the best practice is to use one. 如果您需要一个反应性框架,最佳实践是使用一个。 RxJava is great. RxJava很棒。

In simple-react we solved this problem by using (simple-react) async Queues (an async wrapper over JDK Queue data-structures) that JDK Streams could read from. 简单反应中,我们通过使用JDK Streams可以读取的(简单反应) 异步队列 (JDK Queue数据结构的异步包装器)解决了这个问题。 If the Queue is closed, the Stream will automatically disconnect. 如果队列关闭,流将自动断开连接。

The fast producer / slow consumer problem can be solved by the Queues. 快速生产者/缓慢消费者问题可以通过队列解决。 If the (simple-react) async Queue is backed by a bounded Blocking Queue, it will automatically slow down (block) any producing threads once the Queue gets full. 如果(简单反应)异步队列由有界的阻塞队列支持,则一旦队列已满,它将自动减慢(阻塞)任何正在产生的线程。

In contrast, the LazyFutureStream stream implementation uses non-blocking Queues internally and will even attempt to turn itself from consumer of data from the Queue, to a producer, if there is no data present (and as such it can operate as an entirely non-blocking Stream) 相比之下,LazyFutureStream流实现在内部使用非阻塞队列,甚至在不存在数据的情况下,甚至会尝试将自身从队列中的数据使用者转变为生产者(因此,它可以作为完全非阻塞的对象进行操作)。阻止流)

Example Using PushableStreamBuilder : 使用PushableStreamBuilder的示例:

 PushableLazyFutureStream<Integer> pushable = new PushableStreamBuilder()
            .withBackPressureAfter(100)
            .withBackPressureOn(true)
            .pushableLazyFutureStream();

    // pushable.getInput().fromStream(input); would also be acceptable to add input data
    pushable.getInput().add(100); 
    pushable.getInput().close();

    List list = pushable.getStream().collect(Collectors.toList());

     //list is [100]

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

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