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

返回Java流中的第一个结果匹配谓词或所有不匹配的结果

况庆
2023-03-14

我有一个Validator接口,它提供了一个isValid(Thing)方法,返回一个ValidationResult,其中包含一个布尔值和一条原因消息。

我想创建此接口ValidatorAggregator实现,它跨多个Validators执行OR(如果任何Validator返回正结果,则结果为正)。如果任何验证器成功,我想短路并只返回其结果。如果没有验证器成功,我想返回所有失败消息。

我可以使用流和findFirst()简洁地实现这一点。orElse(…)但是如果findFirst返回空值,则使用此模式我将丢失所有中间结果:

public ValidationResult isValid(final Thing thing) {
    return validators.stream()
      .map(v -> validator.isValid(thing))
      .filter(ValidationResult::isValid)
      .findFirst()
      .orElseGet(() -> new ValidationResult(false, "All validators failed'));
}

是否有任何方法可以使用流捕获失败的结果,或者确实比下面更简洁?

public ValidationResult isValid(final Thing thing) {
    final Set<ValidationResult> failedResults = new HashSet<>();
    for (Validator validator : validators) {
        final ValidationResult result = validator.isValid(thing);
        if (result.isValid()) {
            return result;
        }
        failedResults.add(result);
    }
    return new ValidationResult(false, "No successful validator: " + failedResults); 
    // (assume failedResults stringifies nicely)
}

编辑:根据评论,我同意我试图做的是过早的优化(特别是因为这些验证器非常轻量级)。我可能会采用类似于Holger的解决方案,即计算所有验证并划分为成功/不成功的结果。

这被标记为你能把一个流分成两个流吗?和分区By答案排序是,但我认为这个问题是问,讨论回答,一个不同的问题。


共有1个答案

阴高刚
2023-03-14

没有一个完美的解决方案能以同样的效率处理所有案件。即使是满足短路和只处理一次验证器的条件的循环变量,也有创建和填充集合的缺点,如果只有一次验证成功,这些集合可能是不必要的。

选择取决于与操作相关的实际成本以及至少一次成功验证的可能性。如果以最佳性能处理常见案例,可能会超过解决方案对处理不常见案例的惩罚。

所以

// you may use this if the likelihood of a success is high; assumes
// reasonable costs for the validation and consists (repeatable) results
public ValidationResult isValid(final Thing thing) {
    return validators.stream()
      .map(v -> v.isValid(thing))
      .filter(ValidationResult::isValid)
      .findFirst()
      .orElseGet(() -> new ValidationResult(false, "All validators failed"
        + validators.stream().map(v -> v.isValid(thing)).collect(Collectors.toSet())));
}
// you may use this if the likelihood of a success is
// very low and/or you intent to utilize parallel processing
public ValidationResult isValid(final Thing thing) {
    Map<Boolean,Set<ValidationResult>> results = validators.stream()
        .map(v -> v.isValid(thing))
        .collect(Collectors.partitioningBy(ValidationResult::isValid, Collectors.toSet()));
    return results.get(true).stream().findAny()
        .orElseGet(() -> new ValidationResult(false,
                             "No successful validator: "+results.get(false)));
}
// if chances of successful validation are mixed or unpredictable
// or validation is so expensive that everything else doesn't matter
// stay with the loop
public ValidationResult isValid(final Thing thing) {
    final Set<ValidationResult> failedResults = new HashSet<>();
    for (Validator validator : validators) {
        final ValidationResult result = validator.isValid(thing);
        if (result.isValid()) {
            return result;
        }
        failedResults.add(result);
    }
    return new ValidationResult(false, "No successful validator: " + failedResults);
}

考虑对列表进行排序,这样成功几率更高的验证器就在开始时…

 类似资料:
  • 我有一个C#代码,使用Elastic搜索类型,它将匹配两个字段。我用的是NEST软件包。 问题是,无论我传入什么文本,它都会返回所有结果。我错过了什么?

  • 你好,我在Java中使用正则表达式时遇到了一个问题。 我试图解析这个: 使用此代码(模式匹配器) 我的问题是,我的regexp只返回模式的第一次出现,即使我有一段时间(matcher.find())。。

  • 我正在为我的 REST API 控制器编写测试,我需要检查返回的 对象中的 值,请参阅此测试方法: 但是测试产生了这个错误: 似乎ID被正确返回,但被序列化为不同的结构。 我的代码有什么问题?

  • 问题内容: 做一个简单的测试时,我就在用Java编写正则表达式 但是在JavaScript中 这里发生了什么?我可以使我的Java regex模式“ q”的行为与JavaScript相同吗? 问题答案: 在JavaScript中,返回与使用的正则表达式匹配的子字符串。在Java中,检查整个字符串是否与正则表达式匹配。 如果要查找与正则表达式匹配的子字符串,请使用Pattern和Matcher类,例

  • 我陷入了java流操作的边缘案例... 我想对以下行为进行编码:“从一个任意的水果篮子中,收集20个最小的,除了最小的梨,因为我们不想那样。” 额外的奖励:来的篮子可能没有任何梨。 null 我不能使用本地布尔值并在筛选第一个pear后将其设置为,因为lambda中的所有局部变量都必须是final的。 最坏的情况是,我可以将篮子一分为二,梨和非梨,对梨进行排序,如果有的话,适当地将它们子列表。这看

  • 当Callable返回与条件匹配的结果时,是否有一种方法可以停止Javas ExecuterService? 我有以下算法(代码A): 平均而言,functionB的运行速度是functionA的5倍(在8个内核上)。 这很好,但不完美。在functionA中,someFunction()在找到结果!=null之前平均被调用大约20次。在functionB中,someFunction()总是被调用