2

I am trying to modify a Map's keys based on conditional logic and struggling. I'm new to Java 8 streams API. Let's say I have a map like this:

Map<String, String> map = new HashMap<>();

map.put("PLACEHOLDER", "some_data1");
map.put("Google", "some_data2");
map.put("Facebook", "some_data3");
map.put("Microsoft", "some_data4");

When I would like to do is find the references of PLACEHOLDER and conditionally change that key to something else based on a boolean condition. I feel like it should be something like the below, but this doesn't even compile of course.

boolean condition = foo();

map = map.entrySet().stream().filter(entry -> "PLACEHOLDER".equals(entry.getKey()))
        .map(key -> {
            if (condition) {
                return "Apple";
            } else {
                return "Netflix";
            }
        }).collect(Collectors.toMap(e -> e.getKey(), Map.Entry::getValue));

I found this question which kind of makes me think maybe I can't do this with Java 8 stream APIs. Hopefully someone better at this than me knows how to do this. Ideone link if you want to play with it.

boltup_im_coding
  • 6,345
  • 6
  • 40
  • 52
  • Can you please clarify more, do you want to change the key or the value? – Youcef LAIDANI Jul 21 '18 at 20:02
  • 1
    @YCF_L the key, which makes things a little weirder. – boltup_im_coding Jul 21 '18 at 20:05
  • Could you please edit your question in that case - "_... and conditionally change it's value to something else_" is what was causing confusion. Normally that would mean "change the value associated with that key". – Boris the Spider Jul 21 '18 at 20:06
  • Let us know if you solved your problem. If you did, please [accept](https://stackoverflow.com/help/someone-answers) the most helpful answer, or add your own answer explaining how you solved it. – Tomasz Linkowski Jul 28 '18 at 11:47

2 Answers2

5

You've filtered out all elements that aren't PLACEHOLDER. You need to add that filter logic to your map operation:

final Map<String, String> output = input.entrySet().stream()
        .map(e -> {
            if (!e.getKey().equals("PLACEHOLDER")) {
                return e;
            }
            if (condition) {
                return new AbstractMap.SimpleImmutableEntry<>("Apple", e.getValue());
            }
            return new AbstractMap.SimpleImmutableEntry<>("Netflix", e.getValue());
        }).collect(toMap(Map.Entry::getKey, Map.Entry::getValue));

But as you are guaranteed to only have a single instance of PLACEHOLDER in the Map, you can just do

String placeholderData = input.remove("PLACEHOLDER");
if (placeholderData != null) {
    input.put(condition ? "Apple" : "Netflix", placeholderData);
}
Boris the Spider
  • 59,842
  • 6
  • 106
  • 166
5

If you really want to do it using Streams, you just need to move the conditional logic to the collection phase, like that:

boolean condition = true;
map.entrySet().stream().collect(Collectors.toMap(
        entry -> mapKey(entry.getKey(), condition), Map.Entry::getValue
));

where:

private static String mapKey(String key, boolean condition) {
    if (!"PLACEHOLDER".equals(key)) {
        return key;
    }
    if (condition) {
        return "Apple";
    } else {
        return "Netflix";
    }
}

However, the second part of Boris the Spider's answer using Map.remove and Map.put seems the best way to go.

Tomasz Linkowski
  • 4,386
  • 23
  • 38