Java 8优雅的方式来处理多个方法调用的顺序沿着失败

jucafojl  于 2022-12-25  发布在  Java
关注(0)|答案(3)|浏览(149)

我需要一个接一个地调用所有步骤,并根据每个步骤的结果更新同一个示例。如果任何特定步骤出现问题,我需要设置failStep字段并停止执行下一个步骤。我需要一些优雅的方法来处理这种情况。我尝试了map操作,但不确定如果步骤失败,如何停止进一步的执行。

package abc.service;

import lombok.Data;
import lombok.ToString;

import java.util.Optional;

public class Test {

    public static void main(String[] args) {
        Test test = new Test();
        test.func();
    }

    public void func() {
        Abc abc = new Abc();
        abc.setId("1234");

        Abc abcd = Optional.ofNullable(abc)
                .map(step1 -> getFirstStep(abc))
                .map(step1 -> getSecondStep(abc))
                .map(step1 -> getThirdStep(abc))
                .orElse(abc);
        System.out.println("Answer: " + abcd);
    }

    private Abc getFirstStep(Abc abc) {
        abc.setStep1("STEP1");
        return abc;
    }

    private Abc getSecondStep(Abc abc) {
        abc.setStep2("STEP2");
        abc.setFailStep("STEP2");
        return abc;
    }

    private Abc getThirdStep(Abc abc) {
        abc.setStep3("STEP3");
        return abc;
    }
}

@Data
@ToString
class Abc {
    private String id;
    private String step1;
    private String step2;
    private String step3;
    private String failStep;
}

一个简单的方法是在所有步骤方法中添加空检查。

private Abc getThirdStep(Abc abc) {
    if(abc.getFailStep() == null) {
        abc.setStep3("STEP3");
    }
    return abc;
}

任何建议,以处理这个更好和优雅的方式。

vom3gejh

vom3gejh1#

您可以通过返回Optional来获得想要的行为,这样空结果就向flatMap链的其余部分发出失败信号。

public void func() {
        Abc abc = new Abc();
        abc.setId("1234");

        Abc abcd = Optional.ofNullable(abc)
                .flatMap(this::getFirstStep)
                .flatMap(this::getSecondStep)
                .flatMap(this::getThirdStep)
                .orElse(abc);
        System.out.println("Answer: " + abcd);
    }

    private static Optional<Abc> toReturn(Abc abc) {
      return abc.getFailStep() == null ? Optional.of(abc) : Optional.empty();
    }
    
    private Optional<Abc> getFirstStep(Abc abc) {
        abc.setStep1("STEP1");
        return toReturn(abc);
    }

    private Optional<Abc> getSecondStep(Abc abc) {
        abc.setStep2("STEP2");
        abc.setFailStep("STEP2");
        return toReturn(abc);
    }

    private Optional<Abc> getThirdStep(Abc abc) {
        abc.setStep3("STEP3");
        return toReturn(abc);
    }

但是我强烈建议不要使用这样的代码。每个阅读它的人都会浪费5分钟来弄清楚它是如何工作的。如果是50个人的话,你已经浪费了将近4个小时加上所有的努力来发明这个诡计。
只需将其分解为一个平面函数,并使用一系列“if”保护。

Abc createAbcAndApplySteps() {
  Abc abc = new Abc();
  abc.setId("1234");
  doFirstStep(abc);
  if (abc.getFailStep() != null) return abc;
  doSecondStep(abc);
  if (abc.getFailStep() != null) return abc;
  doThirdStep(abc);
  return abc;
}

或者更好的方法是在标记错误时抛出一个异常。它们在语言中可以使错误处理干净。

// Call 
  private static void fail(Abc abc, String failMsg) {
    abc.setFailStep(failMsg);
    throw AbcStepFailureException("Fail: " + failMsg);
  }

我向你保证,任何一个了解自己工作的技术领导都会更喜欢第三个和第二个习惯用法,而不是第一个。“优雅”通常只是一个表示默默无闻的花哨词汇。

daupos2t

daupos2t2#

你也可以反过来做,不是从abc创建Optional,而是从函数中创建一个序列(列表或其他),比如:

public void func() {
        Abc abc = new Abc();
        abc.setId("1234");

        Function<Abc, Abc> f1 = input -> getFirstStep(input);
        Function<Abc, Abc> f2 = input -> getSecondStep(input);
        Function<Abc, Abc> f3 = input -> getThirdStep(input);

        Abc abcd = doStuff(abc, List.of(f1, f2, f2));

        System.out.println("Answer: " + abcd);
    }

    public Abc doStuff(Abc input, List<Function<Abc, Abc>> functions) {
        if (functions.isEmpty()) return input; //no more functions to apply
        else {
            final var function = functions.get(0);
            final var remainingFunctions = functions.subList(1, functions.size());
            final var abc = function.apply(input);
            if (abc.getFailStep() != null) {
                //Short circuit here
                return abc;
            } else {
                //continue applying the rest of the functions
                return doStuff(abc, remainingFunctions);
            }
        }
    }

这将在步骤2之后终止。不要使用异常来控制程序流。

lp0sw83n

lp0sw83n3#

首先,这是Optinal.map()错误用法。该实用程序应仅在给定函数(例如:getFirstStep(),getSecondStep())可能返回空值。
但是如果你仍然需要在这里使用Optinal,有两种方法,但都有自己的缺点。
1.使用定制的RuntimeException,从函数中抛出它,并在调用map方法的地方捕获它。
1.如果某个步骤失败,将其设置为ABC对象并返回null,您可以从abc而不是abcd获取失败信息,在这种情况下,Map方法将执行3次,但在您返回null后将不执行任何函数。

相关问题