xetra11
xetra11

Reputation: 8837

How to translate a Optional mapping to Stream mapping in Java

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.

Upvotes: 2

Views: 143

Answers (3)

Naman
Naman

Reputation: 31868

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());

Upvotes: 1

ernest_k
ernest_k

Reputation: 45309

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.

Upvotes: 2

Eran
Eran

Reputation: 393781

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);

Upvotes: 2

Related Questions