Java 8 个流 - 将固定数量的谓词过滤器应用于单个流

Java 8 Streams - Apply fixed amount of predicate filters to single Stream

有没有办法将固定数量的 Predicates 应用于打开的 Stream ?我真的无法让我的任何尝试工作。要么尝试以流关闭错误结束,要么没有应用所有过滤器。

示例:

 // list of all JLabels of any container
private final List<JLabel> listOfLabels = new ArrayList<>();
// set of user-defined filters
private final Set<Predicate<JLabel>> filters = new HashSet<>();

// let's add some filters
filters.add(label -> label.getBackground() == Color.RED);
filters.add(label -> label.getWidth() > 500);

如何将所有过滤器应用于 listOfFiles 的流?假设我们要隐藏 JLabels 不匹配这些过滤器。我正在寻找类似下面的非工作代码片段的东西。

public void applyFilters() {
   listOfLabels.forEach(label -> label.setVisible(false)); // hide all labels
   Stream<JLabel> stream = listOfLabels.stream();
   filters.forEach(stream::filter);
   stream.forEach(label -> label.setVisible(true));
   // stream closed error
}

执行方法 applyFilters() 后,容器应该只有与 filters 集定义的所有谓词相匹配的可见标签。 (本例中的红色背景和宽度大于 500)。

当您使用 Stream 时,您必须始终使用 link 到 Stream 对象,该对象是 return 通过应用先前的操作。 从 API:

可以看出
Stream<T> filter(Predicate<? super T> predicate);

Stream 对象是 returned 并且 javadoc 说:

Returns a stream consisting of the elements of this stream that match * the given predicate.

考虑到这一点,对于您的情况,我们可以应用如下内容:

转换:

filters.forEach(stream::filter);

收件人:

   for (Predicate<JLabel> filter : filters) {
        stream = stream.filter(filter);
   }

这应该可行,因为现在您将 link 更新为 Stream 对象并遵循文档。

试试这个。

public void applyFilters() {
    listOfLabels.forEach(label -> label.setVisible(false));
    listOfLabels.stream()
        .filter(label -> filters.stream()
            .allMatch(predicate -> predicate.test(label)))
        .forEach(label -> label.setVisible(true));
}

您可以先通过 Predicate::and 运算符将所有过滤器缩减为一个过滤器:

Predicate<JLabel> allFilters = filters.stream()
    .reduce(Predicate::and)
    .orElse(t -> true);

然后,使用这个简化的过滤器过滤:

listOfLabels.forEach(label -> label.setVisible(false));

listOfLabels.stream()
    .filter(allFilters)
    .forEach(label -> label.setVisible(true));

对于这最后一步,您可能还想采用稍微不同的方法:

listOfLabels.forEach(label -> label.setVisible(allFilters.test(label)));

这样做的好处是只需要遍历一次标签。