How to translate a Optional mapping to Stream mapping in Java

138 views Asked by At

I have this current logic:

    List<String> priceUnitCodes = ofNullable(product.getProductPrices())
            .map(ProductPrices::getProductPrices)
            .flatMap(productPrices -> productPrices.stream()) // << error highlight
            .map(ProductPrice::getPriceBase)
            .map(PriceBase::getPriceUnit)
            .map(UniversalType::getCode)
            .collect(Collectors.toList());

Where in IntelliJ the flatMap part is highlighted and shows the following error hint:

no instance(s) of type variable(s) U exist so that Stream<ProductPrice> conforms to  Optional<? extends U>

I know that Optionals and Stream are two different things but I wonder if there is a way to combine them so I can follow up an Optional<List<?>> with a Stream afterwards.

3

There are 3 answers

0
ernest_k On BEST ANSWER

If you're on Java 9+, you can use Optional.stream, followed by flatMap:

ofNullable(product.getProductPrices())
.map(ProductPrices::getProductPrices)
.stream()
.flatMap(Collection::stream) //assuming getProductPrices returns a Collection
...

Optional.stream returns an empty stream if the optional is empty.

3
Eran On

Since you are starting with an Optional, you have to decide what to return when that Optional is empty.

One way is to put the Stream pipeline inside the Optional's map:

List<String> priceUnitCodes = ofNullable(product.getProductPrices())
        .map(ProductPrices::getProductPrices)
        .map(productPrices -> productPrices.stream()
                                           .map(ProductPrice::getPriceBase)
                                           .map(PriceBase::getPriceUnit)
                                           .map(UniversalType::getCode)
                                           .collect(Collectors.toList())
        .orElse(null);

Or course, if the map operations inside the Stream pipeline may return null, additional changes will be required (to avoid NullPointerException).

On the other hand, if they can never return null, they can be chained into a single map:

List<String> priceUnitCodes = ofNullable(product.getProductPrices())
        .map(ProductPrices::getProductPrices)
        .map(productPrices -> productPrices.stream()
                                           .map(pp -> pp.getPriceBase().getPriceUnit().getCode())
                                           .collect(Collectors.toList())
        .orElse(null);
0
Naman On

An alternate solution would be to get the value of the Optional using orElse and this can be done without upgrading to Java-9. It would look like:

List<String> priceUnitCodes = Optional.ofNullable(product.getProductPrices())
            .map(ProductPrices::getProductPrices)
            .orElse(Collections.emptyList()) // get the value from Optional
            .stream()
            .map(ProductPrice::getPriceBase)
            .map(PriceBase::getPriceUnit)
            .map(UniversalType::getCode)
            .collect(Collectors.toList());