sidss sidss - 3 months ago 8
Java Question

Process list stream and collect into map/ImmutableMap with only non null values

How to process a list of string and collec it into Map or Immutable map only for those whose value is present

String anotherParam = "xyz";
Map.Builder<String,String> resultMap = ImmutableMap.builder(..)

listOfItems.stream()
.filter(Objects::nonNull)
.distinct()
.forEach(
item -> {
final Optional<String> result =
getProcessedItem(item,anotherParam);

if (result.isPresent()) {

resultMap.put(item, result.get());
}
});
return resultMap.build();


Please tell, is there a better way to achieve this via collect?

Answer

If you have access to Apache Commons library you can make use of Pair.class

Map<String, String> resultMap = ImmutableMap.copyof(listOfItems()
    .stream()
    .filter(Objects::nonNull)
    .distinct()
    .map(it -> Pair.of(it, getProcessedItem(it,anotherParam))
    .filter(pair -> pair.getValue().isPresent())
    .collect(toMap(Pair::getKey, pair -> pair.getValue().get())))

But it's a good practice to make special data classes which describes your mapping item->result more specificly

Here is an example, create class like this:

static class ItemResult(){
    public final String item;
    public final Optional<String> result;

    public ItemResult(String item, Optional<String> result){
        this.item = item;
        this.result = result;
    }

    public boolean isPresent(){
        return this.result.isPresent();
    }

    public String getResult(){
        return result.get();
    }
}

And use it like that:

Map<String, String> resultMap = ImmutableMap.copyOf(listOfItems()
    .stream()
    .filter(Objects::nonNull)
    .distinct()
    .map(it -> new ItemResult(it, getProcessedItem(it,anotherParam))
    .filter(ItemResult::isPresent)
    .collect(toMap(ItemResult::item, ItemResult::getResult)))

You can read here why Google gave up the idea of tuples and pairs and don't use them in most cases

If after all you don't want to use any other class you can leverage api of the Optional:

Map.Builder<String,String> resultMap = ImmutableMap.builder(..)

listOfItems.stream()
        .filter(Objects::nonNull)
        .distinct()
        .forEach(item -> getProcessedItem(item,anotherParam)
                         .ifPresent(result -> resultMap.put(item result));
    return resultMap.build();
Comments