使用Streams替换For-Each循环

时间:2015-08-25 16:53:50

标签: java foreach java-8 java-stream

我想使用Java 8 Streams替换以下for-each循环:

for (Rule rule : this.rules) {

    if (rule.getCondition().evaluate(rule, record)) {
        Records.emit(collector, outputStreamMapping.get(rule.getOutputStream()), tuple, recordId, record);
        collector.ack(tuple);

        ruleApplied = true;
        break;
    }
}

if (!ruleApplied) {
    LOGGER.warn("No rule was applied to record {}", record);
    LOGGER.debug("Rules: {}", this.rules);
    ErrorReporter.emitErrorNode(this.collector, recordId, componentName,
            "No matching rule for record " + record, record);
    collector.fail(tuple);
}

我想迭代一组规则,并评估每个规则的条件。如果条件适用,我会对该记录采取行动并停止处理。如果没有应用规则,那么我想记录它并对记录执行不同的处理。

但是,我不确定如何做到这一点。任何帮助和解释将不胜感激。

编辑:

我试过这个:

    this.rules.stream().filter(rule -> rule.getCondition().evaluate(rule, record)).forEach((rule) -> {
        Records.emit(collector, outputStreamMapping.get(rule.getOutputStream()), tuple, recordId, record);
        collector.ack(tuple);

        ruleApplied = true;
        break;
    });

当然,它并不喜欢break语句,并抱怨ruleApplied不是最终的,因为它在lambda范围之外声明。

根据我所看到的答案,似乎循环是最干净的方式。我不确定是否有其他流构造允许我以与在基本循环中所做的不同的方式封装逻辑(即,中断和跟踪布尔)。

EDIT2:

以下是基于此主题建议的解决方案:

Optional<Rule> possibleRule = rules.stream().filter(rule -> rule.getCondition().evaluate(rule, record))
        .findFirst();

if (possibleRule.isPresent()) {
    Records.emit(collector, outputStreamMapping.get(possibleRule.get().getOutputStream()), tuple, recordId,
            record);
    collector.ack(tuple);
} else {
    LOGGER.warn("No rule was applied to record {}", record);
    LOGGER.debug("Rules: {}", this.rules);
    ErrorReporter.emitErrorNode(this.collector, recordId, componentName,
            "No matching rule for record " + record, record);
    collector.fail(tuple);
}

2 个答案:

答案 0 :(得分:6)

你可以做到

Optional<Rule> rule = rules.stream().
                       .filter(rule -> rule.getCondition().evaluate(rule, record))
                       .findFirst();
if (rule.isPresent()) {
    Records.emit(collector, outputStreamMapping.get(rule.get().getOutputStream()), 
                 tuple, recordId, record);
    collector.ack(tuple);

    ruleApplied = true;
}

答案 1 :(得分:1)

您应该可以使用Stream anyMatch方法和执行Predicate等必要副作用的Records.emit来执行此操作。< / p>

boolean ruleApplied = this.rules.stream().anyMatch(
    rule ->
    {
        boolean match = rule.getCondition().evaluate(rule, record);
        if (match)
        {
            Records.emit(collector, outputStreamMapping.get(rule.getOutputStream()), tuple, recordId, record);
            collector.ack(tuple);
        }
       return match;
   }
);

anyMatch method是一种短路操作,会在Predicate返回true时停止处理。短路将满足您的break行为。

  

返回此流的任何元素是否与提供的谓词匹配。如果不是确定结果所必需的,则不能评估所有元素的谓词。如果流为空,则返回false并且不评估谓词。

     

这是一种短路终端操作。