AntonBoarf
AntonBoarf

Reputation: 1313

Java8 streams with Map?

I have the following Map (each key is a String and each value is a List<Message>)

My map is like this :

1st entry :"MONDAY" -> [message1, message2, message3]
2nd entry : "TUESDAY" -> [message4, message5]
...

My goal is to change each message content :

I was thinking about this :

map.entrySet().stream().peek(entry -> {
    entry.getValue().stream().peek(m -> m.setMessage(changeMessage()))
})

But don't know how to finish and do it properly.

Upvotes: 2

Views: 100

Answers (3)

Nikolas
Nikolas

Reputation: 44496

Unfortunately, doesn't provide a straightforward way to change the Map values without violating the Side-effects principle:

Side-effects in behavioral parameters to stream operations are, in general, discouraged, as they can often lead to unwitting violations of the statelessness requirement, as well as other thread-safety hazards.

Here is a possible solution:

Map<String, List<Message>> = map.entrySet().stream()
    .map(e -> {                                                      // iterate entries
            e.setValue(e.getValue().stream()                         // set a new value
                .map(message -> {
                    message  -> message.setMessage(changeMessage()); // .. update message
                    return message;})                                // .. use it
                .collect(Collectors.toList()));                      // return as a List
            return e;})                                              // return an updated value
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue));      // collec to a Map

However, Java provides a well-known for-each feature to achieve your goal in a more direct way which is more readable:

for (List<Message> list: map.values()) { 
    for (Message message: list) { 
        message.setMessage(changeMessage()); 
    } 
}

Upvotes: 2

Samuel Philipp
Samuel Philipp

Reputation: 11050

If you just want to update the message of all messages there is no need to use the whole entry set. You can just stream the values of your map and map the items. The use forEach() to update them:

map.values().stream().flatMap(List::stream)
        .forEach(m -> m.setMessage(changeMessage(m.getMessage())));

If you need the key to change the message you can use this:

map.forEach((key, messages) -> messages.forEach(m -> 
        m.setMessage(changeMessage(key, m.getMessage()))));

Upvotes: 0

Akash
Akash

Reputation: 101

Iterate map, change each element of list again put the collected list on the same key of the map.

map.forEach((k,v)->{
                map.put(k, v.stream().map(i->i+"-changed").collect(Collectors.toList()));

            });

Upvotes: 0

Related Questions