Rik*_*Rik 12 java aggregate predicate java-8 java-stream
我有一个Validator提供isValid(Thing)方法的接口,返回ValidationResult包含a boolean和原因消息的方法.
我想创建一个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'));
}
Run Code Online (Sandbox Code Playgroud)
有没有办法使用流捕获失败的结果,或者实际上比下面更简洁?
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)
}
Run Code Online (Sandbox Code Playgroud)
编辑:基于评论,我同意我想要做的是过早优化(特别是因为这些验证器非常轻量级).我可能会采用类似于Holger计算所有验证和分区成功/不成功结果的解决方案.
这被标记为可以将流分成两个流的欺骗?而partitioningBy答案就是这样,但我认为这个问题是在讨论和讨论,这是一个不同的问题.
不存在能够以相同效率处理所有情况的完美解决方案。即使您的循环变体满足短路并仅处理验证器一次的标准,也存在创建和填充集合的缺点,如果只有一次验证成功,则可能会发现没有必要。
\n\n选择取决于与操作相关的实际成本以及至少一次成功验证的可能性。如果以最佳性能处理常见情况,它可能会超过处理不常见情况时解决方案\xe2\x80\x99s 的惩罚。
\n\n所以
\n\n// you may use this if the likelihood of a success is high; assumes\n// reasonable costs for the validation and consists (repeatable) results\npublic ValidationResult isValid(final Thing thing) {\n return validators.stream()\n .map(v -> v.isValid(thing))\n .filter(ValidationResult::isValid)\n .findFirst()\n .orElseGet(() -> new ValidationResult(false, "All validators failed"\n + validators.stream().map(v -> v.isValid(thing)).collect(Collectors.toSet())));\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n// you may use this if the likelihood of a success is\n// very low and/or you intent to utilize parallel processing\npublic ValidationResult isValid(final Thing thing) {\n Map<Boolean,Set<ValidationResult>> results = validators.stream()\n .map(v -> v.isValid(thing))\n .collect(Collectors.partitioningBy(ValidationResult::isValid, Collectors.toSet()));\n return results.get(true).stream().findAny()\n .orElseGet(() -> new ValidationResult(false,\n "No successful validator: "+results.get(false)));\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n// if chances of successful validation are mixed or unpredictable\n// or validation is so expensive that everything else doesn\'t matter\n// stay with the loop\npublic ValidationResult isValid(final Thing thing) {\n final Set<ValidationResult> failedResults = new HashSet<>();\n for (Validator validator : validators) {\n final ValidationResult result = validator.isValid(thing);\n if (result.isValid()) {\n return result;\n }\n failedResults.add(result);\n }\n return new ValidationResult(false, "No successful validator: " + failedResults);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n考虑对列表进行排序,以便成功机会较高的验证者位于开头\xe2\x80\xa6
\n| 归档时间: |
|
| 查看次数: |
137 次 |
| 最近记录: |