使用通过Flow API实现的处理器转换数据流

时间:2018-02-25 18:43:12

标签: java concurrency java-8 java-9 data-stream

我正在浏览Oracle中与Flow.PublisherFlow.Subscriber的并发概念相关的Community#DOC-1006738。在那里可以找到使用具有这两行代码的处理器来转换数据流的示例代码,这让我有些困惑。

//Create Processor and Subscriber  
MyFilterProcessor<String, String> filterProcessor = 
                                      new MyFilterProcessor<>(s -> s.equals("x")); 

问题1. MyFilterProcessor如何在此处为<String, String>类型?

对于我最初的想法,这些可能是<String, Boolean>,但那将违反下一行中订户定义的进一步定义: -

MyTransformProcessor<String, Integer> transformProcessor = 
                              new MyTransformProcessor<>(s -> Integer.parseInt(s));  

附加说明此处,除非我明确地将上述内容强制转换为

MyTransformProcessor<String, Integer>(s -> Integer.parseInt(s))

我在 parseInt 阅读时收到错误, 无法应用于Object

- 为什么我需要在此处显式转换RHS? -

虽然代码主要存在于共享链接中,但我使用的有用构造函数定义是

public class MyTransformProcessor<T, R> extends SubmissionPublisher<R> implements Flow.Processor<T, R> {       
    private Function function;
    MyTransformProcessor(Function<? super T, ? extends R> function) {  
        super();  
        this.function = function;  
    } 
    ...
} 

filterProcessor相同的一个: -

public class MyFilterProcessor<T, R> extends SubmissionPublisher<R> implements Flow.Processor<T, R> {
    private Function function;
    MyFilterProcessor(Function<? super T, ? extends R> function) {
        super();
        this.function = function;
    }
    ...
}

问题。现在有了这些更改(解决问题1后的一个,另外一个来自附加说明),如何正确实现样本?或者我只是错过了一些非常基本的东西?

1 个答案:

答案 0 :(得分:3)

我认为您的主要错误是将MyFilterProcessor作为MyTransformProcessor的(几乎)精确副本实施。

由于作者没有发布所述类的代码,我试图根据以下内容猜测其行为:

... = new MyFilterProcessor<>(s -> s.equals("x"));

名称Filter表明该组件只接受然后重新发布某些值。此时,评估为boolean(或Predicate<T>)的函数在上下文中是完全可以接受的(因此s -> s.equals("x"))。

页面末尾的初始数据流

String[] items = {"1", "x", "2", "x", "3", "x"};  

似乎证实了我的假设。作者只是想过滤掉"x"值,并且这个任务被赋予MyFilterProcessor,它必须在将每个类型发布到管道的其余部分之前对其进行评估。输出类型必须与输入类型相同。

构造函数应该如下所示:

MyFilterProcessor(Predicate<? super R> predicate) { /* ... */ }
// or
MyFilterProcessor(Function<? super R, Boolean> function) { /* ... */ }

onNext据说只转发某些元素:

if (! predicate.test(item)) {
    int max = submit(item); // get the estimated maximum lag
    subscription.request(max);
}

我对MyFilterProcessor的定义有两个想法:

  • 1)public class MyFilterProcessor<T, R> extends SubmissionPublisher<R> implements Flow.Processor<R, R>

因为Flow.Processor意味着接受并转发相同的类型。

我似乎无法在任何地方使用T类型。这就是我被封锁的地方。

  • 2)public class MyFilterProcessor<T, R> extends SubmissionPublisher<R> implements Flow.Processor<T, R>

但是,在onNext中,您必须将<T>投射到<R> (丑陋,非常难看)

if (! predicate.test(item)) {
    int max = submit( (R) item);
    subscription.request(max);
}

在这种情况下,您将测试Predicate<? super T>

如果您愿意稍微重构一下,因为SubmissionPublisher已经继承了Flow.Publisher的行为,您可以让该类只执行Flow.Subscriber

public class MyFilterProcessor<R> extends SubmissionPublisher<R> implements Flow.Subscriber<R>

等等

MyFilterProcessor<String, String> filterProcessor = new MyFilterProcessor<>(s -> s.equals("x"));
// or, if you follow my example:
MyFilterProcessor<String> filterProcessor = new MyFilterProcessor<>(s -> s.equals("x"));

终于有效了。

如果您在MyFilterProcessorMySubscriber内打印值,您将获得此输出:

Publishing Items...
FilterProcessor: Receiving: 1
FilterProcessor: Receiving: x
FilterProcessor: Receiving: 2
FilterProcessor: Receiving: x
FilterProcessor: Receiving: 3
FilterProcessor: Receiving: x
Got: 1
Got: 2
Got: 3

这是预期的结果。

进行测试时,请记住在退出应用程序之前等待管道完成,因为SubmissionPublisher会在另一个Thread中发布元素。

另外,请与文章相反,具有改变的常识

private Function function; 
// ...
submit((R) function.apply(item));  

private Function<? super T, ? extends R> function;
// ...
submit(function.apply(item));
  

为什么我需要在这里明确地投射RHS?

我仍然在努力了解你是如何得到cannot be applied to Object错误的。您使用的是哪个号码和IDE?