Java 8: Change the values of an EntrySet stream

25,100

Solution 1

If you want a Map as result:

Map<Instant, String> getItems() {
    return items.entrySet()
            .stream()
            .collect(Collectors.toMap(
                    Map.Entry::getKey,
                    e -> renderTags(e.getValue())));
}

Solution 2

If you want to modify an existing map instead of generating the new one (as in your example), there's no need to use the stream at all. Use Map.replaceAll:

items.replaceAll((k, v) -> renderTags(v));
return items;

If you want to keep the original map unchanged, consult other answers.

Solution 3

You can try it this way with Collectors.toMap():

Map<Instant, String> getItems() {
    return items.entrySet().stream()
                .collect(Collectors.toMap(
                            Map.Entry::getKey,
                            entry -> renderTags(entry.getValue())
                         ));
}

By the way, if the name says simply "get", you shouldn't generally transform it in there. One expects a getter to be simple and not costy at all.

Solution 4

An alternative could be

Map<Instant, String> getItems() {
return items.entrySet().stream()
           .peek(entry -> entry.setValue(renderTags(entry.getKey())))
           .collect(Collectors.toMap(Map.Entry::getKey,e -> e.getValue()));
}

Useful if you have to perform updates on the stream before collect call.

Share:
25,100
Ruckus T-Boom
Author by

Ruckus T-Boom

Updated on June 30, 2020

Comments

  • Ruckus T-Boom
    Ruckus T-Boom almost 4 years

    I have the following setup:

    Map<Instant, String> items;
    ...
    String renderTags(String text) {
        // Renders markup tags in a string to human readable form
    }
    ...
    <?> getItems() {
        // Here is where I need help
    }
    

    My problems is, the strings that are the values of the items map are marked up with tags. I want getItems() to return all the items, but with the strings parsed using the renderTags(String) method. Something like:

    // Doesn't work
    items.entrySet().stream().map(e -> e.setValue(renderTags(e.getValue())));
    

    What is the most effective way to do this?

  • Vlasec
    Vlasec almost 9 years
    Oh well, you were almost a full minute faster :/
  • Ruckus T-Boom
    Ruckus T-Boom almost 9 years
    Can either of you tell me why I'd get a Cannot resolve method 'getKey' on the line Map.Entry::getKey?
  • Didier L
    Didier L almost 9 years
    Are you sure that your Map import is really java.util.Map?
  • Ruckus T-Boom
    Ruckus T-Boom almost 9 years
    @DidierL I just checked to make sure and it is.
  • Ruckus T-Boom
    Ruckus T-Boom almost 9 years
    Sorry, I figured it out. It was a typo in the method return type, that was somehow showing up as the error I mentioned. Fixed that and it works great :)
  • Ruckus T-Boom
    Ruckus T-Boom almost 9 years
    Not what I need here (the new map is just for display purposes), but I didn't know that, so I'll file it away for later. Thanks!
  • Ruckus T-Boom
    Ruckus T-Boom almost 9 years
    What are the advantages/disadvantages of doing it this way versus the way shown in the accepted answer?
  • Max
    Max almost 9 years
    it depends on context (not the one of the question)... I havn't yet used the peek method but I keep in mind it exists.
  • Ruckus T-Boom
    Ruckus T-Boom almost 9 years
    Sounds good. I use it a lot for debugging (just shooting the result to System.err), but I've never thought to use it like this.
  • Max
    Max almost 9 years
    Me too :) And I havn't been in the case of a sequence of changes to apply to a collection or map.
  • Vlasec
    Vlasec almost 9 years
    Yep, to the victor go the spoils.
  • Vlasec
    Vlasec almost 9 years
    What does exactly happen when you modify an entry? I think it changes the map and the action called in peek should be non-interfering. It is good for logs, but if I got it, it shouldn't be used this way, as far as I know.
  • Max
    Max almost 9 years
    You have to think your map with references of objects. Updating the value of an entry doesn't affect the map itself (nor the result of hashcode and equals mechanism used on keys for storing elements).
  • Max
    Max almost 9 years
    And this remark is valid for collections in general. When iterating on a collection, you can update the elements inside. Not the collection itself.
  • Nicholas DiPiazza
    Nicholas DiPiazza over 6 years
    yeah this is the solution i needed. if you don't want a new map, use this.
  • рüффп
    рüффп over 4 years
    +1 for giving a solution to alter the original map. Exactly what I was looking for. Note that with the accepted answer it can also work but the original Map must be merged with the altered keys like oMap.putAll(alteredMap). Method peek prevent to do this.
  • user1803551
    user1803551 about 2 years
    Don't perform operations in peek, they are not guaranteed to execute. It's only for debugging purposes.
  • Max
    Max almost 2 years
    Yes, definitely, I update my answer.
  • user1803551
    user1803551 almost 2 years
    That doesn't help at all. peek should not perform any operation with side effects. It's meant to be used to print intermediate results.
  • Max
    Max almost 2 years
    baeldung.com/java-streams-peek-api. the last paragraph describes clearly the same use case in a non debugging context: "we want to alter the inner state of an element". Even if I try to avoid this situation, I conceive it can occurs. That's why I may have used at least once in my carrer.