如何在Java8中过滤和映射parallelStream后收集结果?

时间:2017-11-05 17:03:06

标签: java java-8 java-stream

我想从另一个集合中提取一组对象。要过滤的对象必须是特定类型(或子类型),并且必须与给定的Shape相交。我想用parallelStream

来做

我有以下代码:

public class ObjectDetector {
...
    public ObjectDetector(final Collection<WorldObject> objects,
        final BiFunction<Shape, Shape, Boolean> isIntersecting) {
    ...
    }

    public List<ISensor> getSonarObjects(final Shape triangle) {
        return selectIntersecting(triangle, ISensor.class);
    }

    private <T> List<T> selectIntersecting(Shape triangle, Class<T> type) {
        return objects.parallelStream()
                .filter(o -> type.isInstance(o) && isIntersecting.apply(o.getShape(), triangle))
                .map(o -> type.cast(o)).collect(Collectors.toList());

问题部分在List<T> selectIntersecting(Shape triangle, Class<T> type)方法中,其中objectsCollectionisIntersectingBiFunction<Shape,Shape,Boolean>

当我使用stream()代替parallelStream()时,我的所有测试都是绿色的。所以我可以假设过滤和映射逻辑工作正常。但是,当我尝试使用parallelStream()时,我的测试失败是不可预测的。我能够观察到的唯一一致性是返回的size()的{​​{1}}小于或等于(但当然不会更大)我期望的大小。

例如,失败的测试用例:

List<T>

测试结果是:

  

测试失败:getEvery2Sonar(hu.oe.nik.szfmv.environment.ObjectDetectorTest):声纳可检测的数量应该是预期的3:&lt; 3&gt;但是:&lt; 2&gt;

根据我的理解 - 编写here - 可以将int counter = 0; public BiFunction<Shape, Shape, Boolean> every2 = (a, b) -> { counter++; return counter % 2 == 0 ? true : false; }; @Test public void getEvery2Sonar() { assertEquals("base list size must be 8",8,list.size()); ObjectDetector detector = new ObjectDetector(list, every2); List<ISensor> sonarable = detector.getSonarObjects(triangle); assertEquals("number of sonar detectables should be 3", 3, sonarable.size()); } 收集到非并发parallelStream

我也尝试在Parallelism教程page上找到一些线索,但我还是一无所知。

有人可以请我解释一下我做错了什么吗?

1 个答案:

答案 0 :(得分:3)

你的谓词函数有副作用 - 这对于parallelStream会很糟糕,因为输入流中的评估顺序是非确定性的,而且你没有锁定你的可变状态。

实际上,filter的文档声明 * 谓词必须是stateless

我不确定你在这里尝试实现的行为,所以我不确定什么是合适的&#34;修复&#34;可能是。

*没有双关语。