Liso
Liso

Reputation: 245

Java 8 Map with optional key to map with value of optional as key

I have a Map<Optional, String> and need to get a map with the actual values of the optionals, if they are present (Map<Price, String>).

This works:

private Map<Price, String> getPricesForUserRelatedPrices(List<SpecialPrice> prices) {
    Map<Optional<Price>, String> pricesWithOptional = prices.stream().collect(Collectors.toMap(this::getPrice, this::getName));
    Map<Price, String> existingPrices = pricesWithOptional .entrySet().stream().filter(e -> e.getKey().isPresent()).collect(Collectors.toMap(e -> e.getKey().get(), Entry::getValue));
    return existingPrices;
}

The getPrice might return an optional, therefore the empty entries need to be filtered.

The Map with the optional as key is of course only a temporary map to have it somewhat readable.

In the old fashioned/ non-lambda way I would just do this:

private Map<Price, String> getPricesForUserRelatedPrices(List<SpecialPrice> prices) {
Map<Price, String> existingPrices = new HashMap<>();
for(SpecialPrice p: prices){
    Optional<Price> price = getPrice(p);
    if(price.isPresent())
        existingPrices.put(price.get(), getName(price));
}
return existingPrices;

}

Is there a more elegant way?

Upvotes: 2

Views: 5473

Answers (2)

Aviv
Aviv

Reputation: 31

I would like to add to @Naman's answer:

If getName is costly and you want to keep the functional style, you can defer the invocation to the collection phase:

private Map<Price, String> getPricesForUserRelatedPrices(List<SpecialPrice> prices) {
        return prices.stream()
            .map(p -> Map.entry(getPrice(p), p))
            .filter(e -> e.getKey().isPresent())
            .collect(Collectors.toMap(entry -> entry.getKey().get(),
                entry -> getName(entry.getValue())));
    }

Upvotes: 0

Naman
Naman

Reputation: 31878

Yes there is an alternate only if you completely discard pricesWithOptional after you have derived existingPrices and that is a step back from where you have already reached.

Map<Price, String> existingPrices = prices.stream()
        .map(p -> Map.entry(getPrice(p), getName(p))) // to avoid multiple calls to these
        .filter(e -> e.getKey().isPresent())
        .collect(Collectors.toMap(entry -> entry.getKey().get(),
                Map.Entry::getValue));

Note: If both getPrice and getName are costly and you would likely not make getName unless you are sure of getPrice's presence, I would rather suggest staying with the for loop for readability.

Map<Price, String> existingPrices = new HashMap<>();
for (SpecialPrice specialPrice : prices) {
    Optional<Price> price = getPrice(specialPrice);
    if (price.isPresent()) {
        String name = getName(specialPrice);
        existingPrices.put(price.get(), name);
    }
}

Upvotes: 4

Related Questions