当前位置: 首页 > 知识库问答 >
问题:

如何优雅地反复过滤java流,直到找到单个结果?

权黎昕
2023-03-14

我有以下函数,它试图逐步缩小输入集合的范围,直到找到单个元素,即当发现单个项目时,过滤应该停止,因为应用其他过滤器可能会导致根本不匹配。

public List<MyObject> determinePotentialCandidates(List<MyObject> allCandidates) {

        List<MyObject> candidates = allCandidates.stream()
                                                 .filter(this::firstCondition)
                                                 .toList();

        if (candidates.size() > 1) {

            candidates = candidates.stream()
                                   .filter(this::secondCondition)
                                   .toList();

            if (candidates.size() > 1) {

                candidates = candidates.stream()
                                       .filter(this::thirdCondition)
                                       .collect(Collectors.toList());
            }
            
            // ... and so on
        }

        logResult(candidates);
        return candidates;
    }

随着每增加一个嵌套级别,这变得越来越难阅读,我想知道是否有更简洁的方法来编写这篇文章。

优选地,该方法应最多执行一次每个过滤步骤(尽管输入大小较小且过滤成本较低-对于同一输入可以执行多次),并包含单个出口点。

共有2个答案

欧旻
2023-03-14

我在这里看到了一些选项:

在这两种情况下,我假设条件是已知的。但这使解决方案保持了刚性,并且不可扩展。从您发布的示例中,我不能说您是否在原始解决方案中遵守了一些可靠的原则,例如打开/关闭。

选项:

  1. 应用filter()多次,链接
  2. 如前所述,使用循环在条件列表上迭代

对于这两种情况,我建议进行更多调整。

制作一个抽象类或接口,将条件表示为概念。创建另一个类作为条件提供程序,此条件提供程序将维护条件实例列表。稍后可以通过依赖注入或工厂使用您的条件初始化条件提供程序。

您的类(在本例中是此提供程序的客户端)将接收作为依赖项(构造函数)注入的提供程序。类将向提供程序请求它必须验证的所有条件。您的类将在for循环中使用此条件列表来过滤集合。

这样,您可以灵活地使用哪些条件进行过滤。希望您的代码更易于维护。

希望这对你有帮助。

江正德
2023-03-14

您可以将所有条件放入一个列表中,并在其上循环,在每次迭代中应用一个过滤器,直到只剩下一个元素

List<Predicate<MyObject>> conditions = List.of(this::firstCondition, this::secondCondition, this::thirdCondition /*...*/ );
for(int i = 0; i < conditions.size() && allCandidates.size() > 1; i++)
    allCandidates = allCandidates.stream().filter(conditions.get(i)).toList();
// Note: you may need to check if the list is empty here
return allCandidates;
 类似资料:
  • 并在匹配一些条件后用Java8流对其进行过滤 那将如何完成呢? 上面示例的结果应该是

  • 我想在找到第一个值时终止流的执行。然而,当我运行下面的代码时,它显示,即使第一个方法中存在值,也会调用两个方法。 我登记了文件: 表示 如果存在值,则返回{@code true},否则返回{@code false}。 返回描述此流的第一个元素的{@link Optional},如果流为空,则返回空的{@code Optional}。如果流没有遭遇顺序,那么可以返回任何元素。 所以它满足了第一个条件

  • 现在我有一个列表: 我想得到一个字符串列表,即从map中匹配键值的值,在' pick '列表中找到。所以,我期望得到结果{"f "," a"}。有没有办法用java stream api优雅地做到? 当有一个值时,我会这样做: 但是,当有一个键/选择列表要过滤时,就很难了。

  • 我有这个密码 但是,我有这样的错误消息: 怎么解决这个?

  • 问题内容: 如何在Linux和Windows中正常停止Java进程? 什么时候被调用,什么时候不被调用? 终结器又如何呢? 我可以从外壳向Java进程发送某种信号吗? 我正在寻找最好的便携式解决方案。 问题答案: 在所有未强制终止VM的情况下,都会执行关机挂钩。因此,如果要发出“标准” kill(通过kill命令),则它们将执行。同样,它们将在调用后执行。 但是强行杀死(或),然后它们将不会执行。