Skip to content

How to reduce Optionals to throw an error once

I have the following response coming from a rest call and performing some logic based on what is returned.

This is what I want.

If the overall status code is NOT 200 OR If within the list of SimpleResponse, none of the SimpleResponse objects has a 200 httpCode, throw an error.

The example below is incomplete.

  1. Too much going on there, having an optional within another optional.
  2. And then throwing the same error at 2 different places.
  3. Also if the optional result is null say at responseEntity.getBody(), would want to throw same error too.

Is there a cleaner way to write this?

These are the 2 related objects

@Getter
@Setter
public class SimpleResponses {
    private List<SimpleResponse> simpleResponsesList;
}

@Getter
@Setter
public class SimpleResponse {
    private String httpCode;
    // ... other fields
}

Method calling rest call and throwing error if needed.

public ResponseEntity<SimpleResponses> get() {

    HttpEntity<Object> httpEntity = this.getEntity();
    // restTemplate is from Spring
    ResponseEntity<SimpleResponses> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, SimpleResponses.class);


// START
// This is the logic to throw error depending on output as mentioned above.
// looking for a better way to write this. 

    // if none of the object inside the list has 200 code, throw error
    Optional.ofNullable(responseEntity.getBody())
            .map(SimpleResponses::getSimpleResponses)
            .ifPresent(response -> {
                Optional<SimpleResponse> simpleResponse = response.stream()
                        .filter(responseStream -> responseStream.getHttpCode().equals("200"))
                        .findAny();
                if (!simpleResponse.isPresent()) {
                    throw new CustomRuntimeException("Failed ..... "); // repetitive same error being thrown again below.
                }
            });

    // if overall code is not 200, throw error too 
    if (!responseEntity.getStatusCode().is2xxSuccessful()) {
        throw new CustomRuntimeException("Failed ..... ");
    }

// END


    return responseEntity;
}

Answer

Using Optional::flatMap and Optional::ifPresentOrElse the following solution may be offered:

Optional.ofNullable(responseEntity.getBody())
    .flatMap(body -> SimpleResponses.getSimpleResponses(body) // SimpleResponses
        .getSimpleResponsesList()
        .stream() // Stream<SimpleResponse>
        .filter(sr -> "200".equals(sr.getHtppCode()))
        .findAny() // Optional<SimpleResponse>
    )
    .ifPresentOrElse( // Java 9
        System.out::println, 
        () -> { throw new CustomRuntimeException("Bad response"); }
    );

For Java 8, Optional::orElseThrow may be used:

SimpleResponse good = Optional.ofNullable(responseEntity.getBody())
    .flatMap(body -> SimpleResponses.getSimpleResponses(body) // SimpleResponses
        .getSimpleResponsesList()
        .stream() // Stream<SimpleResponse>
        .filter(sr -> "200".equals(sr.getHtppCode()))
        .findAny() // Optional<SimpleResponse>
    )
    .orElseThrow(() -> new CustomRuntimeException("Bad response"));

System.out.println(good);