我想从另一个集合中提取一个对象集合。要过滤的对象必须是特定类型(或子类型),并且必须与给定的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()List<T>小于或等于(但绝不会大于)我期望的大小。

一个失败的测试用例,例如:
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());
}

测试结果为:

测试失败:getEvery2Sonar(hu.oe.nik.szfmv.environment.ObjectDetectorTest):应检测到的声纳数量应为3:但为:

以我的理解-正如here所写-可以将parallelStream收集为非并行Collection

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

有人可以向我解释我做错了什么吗?

最佳答案

您的谓词函数有副作用-与parallelStream一起使用会很糟糕,因为输入流中的求值顺序是不确定的,而且您没有锁定可变状态。

实际上, filter 的文档指出*谓词必须为stateless

我不确定您要在此处实现哪种行为,因此不确定是否可以使用适当的“修复程序”。

*无双关语。

10-07 13:36