将循环内的复杂条件逻辑转换为流和 lambda

Translate complex conditional logic inside a loop into streams and lambdas

我正在寻找一种干净的方法来将具有 ifelse 语句的复杂逻辑条件 导致不同的操作 ,转换为 lambda 和流。

假设我有这个代码:

List<OuterData> result = new LinkedList<>();

for (Outer outer : getOutersFromSomewhere()) {
    OuterData outerData = new OuterData();

    if (outer.isImportant()) {
        doImportantAction(outer, outerData);
    } else if (outer.isTrivial()) {
        doTrivialAction(outer, outerData);
    } else {
        doDefaultAction(outer, outerData);
    }

    for (Inner inner : outer.getInners()) {
        if (inner.mustBeIncluded()) {
            InnerData innerData = new InnerData();

            if (inner.meetsCondition1()) {
                doAction1(inner, innerData, outer, outerData);
            } else if (inner.meetsCondition2()) {
                doAction2(inner, innerData, outer, outerData);
            } else {
                doDefaultAction(inner, innerData, outer, outerData);
            }
            outerData.add(innerData);
        }
    }
    result.add(outerData);
}

return result;

这是从我的真实代码中简化而来的。我知道它可以优化和重构,即我可以将内部 for 移动到 private 方法。我想知道如何将 ifelse ifelse 部分转换为流和 lambda。

我知道如何翻译这个例子的骨架。我会使用 List.stream()Stream.map()Stream.filter()Stream.collect()Stream.peek()。我的问题仅在于条件分支。我该如何翻译?

第一个明显的方法是流式传输您的元素,根据需要的标准过滤它们,然后对每个剩余元素应用操作。这也使代码更清晰:

List<Outer> outers = getOutersFromSomewhere();
outers.stream().filter(Outer::isImportant)
    .forEach(outer -> doImportantAction(outer, outerDate));
outers.stream().filter(Outer::isTrivial)
    .forEach(outer -> doTrivialAction(outer, outerDate));
// default action analog

注意:这仅在重要元素、琐碎元素和默认元素形成 分区 时才有效。否则它不等同于您的 if-else-结构。但也许这是有意的......

这种方法的主要问题:它不是很好的 OOP。您正在查询对象以做出决定。但是OOP应该尽可能"tell, don't ask"。

所以另一种解决方案是在您的 Outer class:

中提供一个消费方法
public class Outer {
    ...
    public void act(OuterData data, Consumer<Outer> importantAction,
            Consumer<Outer> trivialAction, Consumer<Outer> defaultAction) {
        if (isImportant())
            importantAction.accept(this, data);
        else if (isTrivial())
            trivialAction.accept(this, data);
        else
            defaultAction.accept(this, data);
    }
}

现在你这么简单的称呼它:

List<Outer> outers = getOutersFromSomewhere();
outers.forEach(outer -> outer.act(...)); // place consumers here (lambdas)

这有一个明显的优势:如果您必须向您的 Outer class 添加一个功能 - 比方说 isComplex() - 您只需更改该单一的内部结构class(并可能解决其他部分的编译器故障)。或者您可以以向后兼容的方式添加此功能。

相同的规则可以应用于 Inner class 和迭代。