Refactoring a sequence of methods

Fraser :

I have a sequence of methods that I need to run sequentially, using the result of each method as a parameter in the next. However, I also check that the result of each method is "good" before calling the next method (if it's "bad" then I exit the method early. The methods return an empty Optional if they were not successful.

Is there a refactoring that I can perform to improve the code? Chain of Responsibility feels a little overboard.

private boolean isSequenceSuccessful() {
  Optional<byte[]> result1 = doSomething();

  if (!result1.isPresent()) {
    return false;
  }

  Optional<byte[]> result2 = doAnotherThing(result1.get());

  if (!result2.isPresent()) {
    return false;
  }

  Optional<byte[]> result3 = doSomethingElse(result2.get());

  if (!result3.isPresent()) {
    return false;
  }

  return doMoreStuff(result3.get());
}

I don't want to use Exceptions to control the flow of the method because that's a code smell (I expect to sometimes get "bad" results).

LuCio :

You can write it shorter using Optional and mapping:

private boolean isSequenceSuccessful() {
    return Optional.of(doSomething())
            .flatMap(result1 -> doAnotherThing(result1))
            .flatMap(result2 -> doSomethingElse(result2))
            .map(result3 -> doMoreStuff(result3))
            .orElse(false);
}

Or using method references even shorter:

private boolean isSequenceSuccessful2() {
    return Optional.of(doSomething())
            .flatMap(this::doAnotherThing)
            .flatMap(this::doSomethingElse)
            .map(this::doMoreStuff)
            .orElse(false);
}

It depends what you prefer. If you want to keep the intermediate result variables use the lambda version.

Since the methods doAnotherThing and doSomethingElse do return an Optional<byte[]>, Optional.flatMap is needed to continue the mapping. Otherwise you could change the return type of these methods to return byte[] solely. Then you would use Optinal.map only, which would be more consistent.

The mapping will only be performed as long as a value is present in the Optional. If all mappings could be applied the value of the last is returned as result. Otherwise the processing will fail fast and bypass all remainig mappings to the last statement orElse and return it's value. This is false according to your code.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=77719&siteId=1