我已经用Google搜索了很多,但是没有找到答案。
这是我所拥有的:

    parentList.forEach(p -> {
        childList
                .stream()
                .filter(c -> p.id() == c.parentId())
                .<...continue working on stream...>
    });

我似乎找不到一种方法来用谓词替换“过滤器”部分,因为我似乎需要将参数传递给谓词?

最佳答案

您的问题是您每次都使用不同的谓词,因为尽管c是谓词的参数,但p也有所不同:

final Node p;
Predicate<Node> matchesParentId = c -> p.id() == c.id();

您现有的代码可以编译的原因是p实际上在forEach块的范围内是最终的,因此它可以用作该范围内Predicate的最终字段,生存期为forEach迭代一次。

您可以这样做:
parentList.forEach(p -> {
    childList
            .stream()
            .filter(matchesId(p))
            .<...continue working on stream...>
});

private Predicate<Node> matchesId(Node other) {
     return node -> node.id() == other.id();
}

但是您将无法创建一个Predicate并随着p的变化而重复使用它。

您可以将BiPredicatecurry写入Predicate。不幸的是,Java没有提供咖喱方法,因此您必须提供自己的方法。
private <T,U> Predicate<U> curry(BiPredicate<T,U> biPredicate, T t) {
    return u -> biPredicate.test(t, u);
}

BiPredicate<Node,Node> nodesMatch = (a,b) -> a.id() == b.id();

parentList.forEach(p -> {
    childList
        .stream()
        .filter(curry(nodesMatch, p))
        .<...continue working on stream...>
});

除了以前的解决方案之外,这并不能为您带来太多收益,但是它有点像FP。您仍在为每个Predicate创建一个新的p。当然,您可以内联它而不是使用curry()方法。
.filter(c -> nodesMatch.test(p, c))

这确实意味着您可以选择BiPredicate<Node,Node>来动态插入。如果您的BiPredicate初始化起来很昂贵,那么通过循环封装它的许多Predicates就会很便宜。

或者,您可以将pc映射到一个对象中,这使您可以将整个内容提交给谓词:
Predicate<Pair<Node,Node>> nodesMatch = pair ->
    pair.left().id() == pair.right().id();

parentList.forEach(p -> {
    childList
        .stream()
        .map(c -> new Pair<Node>( c, p))
        .filter(nodesMatch)
        .map( pair -> pair.left() )
        .<...continue working on stream...>
});

(此处的Pair是假设的,但是许多3rd party库(例如Guava)提供了一个库,或者您可以自己滚动或使用new Node[] { c, p })

08-05 17:44