如何优雅地过滤java流反复,直到一个单一的结果被发现?



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

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;
}

由于每增加一个嵌套级别,这变得更难阅读,我想知道是否有更简洁的方法来写它。

最好的方法应该执行每个过滤步骤最多一次(尽管输入规模小和过滤便宜——这可能好多次执行相同的输入),包含一个出口点。

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

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;

我看到一些选项:

在这两种情况下,我都假设事先知道条件。但这使解决方案保持刚性,不可扩展。从你发布的例子中,我不能说你是否在你最初的解决方案中观察到一些坚实的原则,例如打开/关闭。

选项:

  1. 多次应用filter(),串联。
  2. 如前所述,使用循环遍历条件列表。

对于这两种情况,我建议再做一些调整。

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

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

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

希望这对你有帮助。

相关内容

  • 没有找到相关文章

最新更新