【发布时间】:2018-08-06 11:11:16
【问题描述】:
我有一个Validator 接口,它提供了一个isValid(Thing) 方法,返回一个ValidationResult,其中包含一个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'));
}
有什么方法可以使用流捕获失败的结果,或者比下面的更简洁?
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)
}
编辑:基于 cmets,我同意我正在尝试做的是过早优化(特别是因为这些验证器非常轻量级)。我可能会采用类似于 Holger 的计算所有验证并划分成成功/不成功结果的解决方案。
这被标记为 Can you split a stream into two streams? 的欺骗,而 partitioningBy 的答案是,但我认为这个问题是在问,而讨论的答案是另一个问题。 p>
【问题讨论】:
-
非流实现将很难被击败。
-
您的流解决方案,即使没有保存中间结果的功能,在我看来也不比非流解决方案更简洁。
-
正如其他人提到的,很难获得短路行为。另一方面,考虑这是否不是过早优化的情况。
-
你可以为此旋转一个自定义收集器,但是它不会像你的 for 循环那样既短也不短路,所以坚持下去
-
任何变体都是一种权衡,可能会执行不必要的操作。您应该使用最适合可能性最高的情况的变体。
标签: java java-8 java-stream aggregate predicate