【问题标题】:Break or return from java 8 map reduce in functional interface在功能接口中从 java 8 map reduce 中断或返回
【发布时间】:2019-11-15 20:12:37
【问题描述】:

我有一个 java 8 功能接口,它接受应用于对象的验证器列表并返回验证结果。验证结果在reduce阶段累积。代码如下:

public interface LogicalTableValidator extends Function<LogicalTable, ValidationResult> {

    static LogicalTableValidator addAll(LogicalTableValidator... validators) {

        //  Need to break out of this validator stream, based on the criticality of a particular validation error
        return logicalTable -> Arrays.stream(validators).map(v -> v.apply(logicalTable))
                .reduce(new ValidationResult(logicalTable.getUid()), (validationResult, currentResult) -> {
                    validationResult.addValidationMessages(currentResult.getValidationMessages());
                    return validationResult;
                });

    }

}

从这里调用此验证逻辑

LogicalTableValidator logicalTableValidators = LogicalTableValidator.addAll(getValidators());
List<ValidationResult> ltValidationResults = logicalTables.stream()
                                                          .parallel()
                                                          .map(logicalTableValidators)
                                                          .collect(Collectors.toList());

我面临的问题是,我无法有条件地脱离验证逻辑。当我在逻辑对象上应用验证器时就是这种情况,如果验证失败并出现严重错误,我不需要运行其余的验证器。相反,我需要在此处停止验证过程。

解决方法是不使用 lambda 表达式进行验证,而是使用以下代码。

        return new LogicalTableValidator() {

            @Override
            public ValidationResult apply(LogicalTable t) {
                ValidationResult result = new ValidationResult(t.getUid());
                for (LogicalTableValidator validator : validators) {
                    ValidationResult currentResult = validator.apply(t);
                    List<ValidationMessage> messages = currentResult.getValidationMessages();
                    Boolean exit = false;
                    for (ValidationMessage message : messages) {
                        if(StringUtils.equalsIgnoreCase(message.getSeverity(),  "1")) {
                            exit = true;
                            break;
                        }
                    }
                    result.addValidationMessages(currentResult.getValidationMessages());
                    if (exit) break;
                }
                return result;
            }

        };

看来,不在函数式接口中使用 lambda 表达式,违背了使用函数式接口的目的,但我想不出有条件地跳出验证循环的方法。我可以使用任何替代方法吗?这段代码应该以不同的方式构造吗?

【问题讨论】:

  • 为什么不使用 filter()?
  • filter() 仍将遍历所有对象以检查过滤条件。如果遇到严重错误,我想跳出循环。

标签: java lambda mapreduce java-stream functional-interface


【解决方案1】:

您可以尝试以下方法。在peek 它收集ValidationMessages。在filterfindFirst 中,它在第一条错误消息后停止。替换cmets中提到的takeWhile,也可以查看this

public interface LogicalTableValidator extends Function<LogicalTable, ValidationResult> {

    static LogicalTableValidator addAll(LogicalTableValidator... validators) {

        logicalTable -> {
            ValidationResult result = new ValidationResult(logicalTable.getUid());
            Arrays.stream(validators).map(v -> v.apply(logicalTable))
                    .peek(currentResult -> result.addValidationMessages(currentResult.getValidationMessages()))
                    .filter(currentResult -> currentResult.getValidationMessages().stream()
                            .filter(message -> StringUtils.equalsIgnoreCase(message.getSeverity(), "1"))
                            .count() > 0)
                    .findFirst()
                    .orElse(null);
            return result;
        }
    }

}

【讨论】:

    【解决方案2】:

    有两个不同的东西:1. 破坏logicalTables 流和 2. 破坏validators 流。

    对于logicalTables,您的流是并行的,即使中断是可能的,您也会获得可能不同的结果。

    对于validators 流,Stream.takeWhile 似乎是最接近纯基于流的解决方案。不幸的是,它自 Java 9 起就在 JDK 中,而且它不包含无效的 ValidationResult 到结果流中。外部库中可能存在替代方案,但在我看来,命令式代码目前非常简单且可读。

    【讨论】:

    • 感谢您的评论。我只是想根据验证错误的严重性来突破验证器流。我确实找到了 java 9 Stream.takeWhile,但不幸的是我们在 java 8 中,并且无法很快迁移到 java 9。
    猜你喜欢
    • 2014-06-12
    • 1970-01-01
    • 1970-01-01
    • 2017-09-21
    • 2021-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多