0
public static void main(String[] args) {
    Map<String, String> m = new HashMap<String, String>();
    m.put("a", "One");
    m.put("b", null);

    toUpperKeys1(m); // NullPointerException
    toUpperKeys2(m); // Working fine
    toUpperKeys3(m); // NullPointerException
}

static Map<String, String> toUpperKeys1(Map<String, String> map) {
    // Scenario 1 : Throwing NullPointerExpecption because Map.Entry::getValue is null
    return map.entrySet().stream().collect(Collectors.toMap(e -> e.getKey().toUpperCase(), Map.Entry::getValue));
}

static Map<String, String> toUpperKeys2(Map<String, String> map) {
    // Scenario 2 : Working fine
    Map<String, String> newMap = new HashMap<String, String>();
    map.entrySet().forEach(e -> newMap.put(e.getKey().toUpperCase(), e.getValue()));
    return newMap;
}

static Map<String, String> toUpperKeys3(Map<String, String> map) {
    // Scenario 3: Throwing NullPointerExpecption because e.getValue() is null
    return map.entrySet().stream().collect(Collectors.toMap(e -> e.getKey().toUpperCase(), e -> e.getValue()));
}

Stacktrace:

java.lang.NullPointerException
    at java.util.HashMap.merge(HashMap.java:1225)
    at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
    at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
    at java.util.HashMap$EntrySpliterator.forEachRemaining(HashMap.java:1699)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:566)
    at com.project.Demo.toUpperKeys1(Demo.java:25)
    at com.project.Demo.main(Demo.java:17)

As Scenario 2 (for-each loop) is working fine but Scenario 1 (Map.Entry::getValue) and Scenario 3 (e -> e.getValue()) both throwing NPE.

Why toMap has this issue, while in concept of hash map null is allowed in both key and values?

Please explain.

Prem
  • 316
  • 1
  • 5
  • 23
  • 3
    please show the stacktrace – Lino Mar 26 '20 at 17:00
  • you have a return statement in the first line , so isn't the code after that is unreachable – Abhinav Chauhan Mar 26 '20 at 17:05
  • @AbhinavChauhan Yeah that is fair but it looks like he's showing 2 separate options, 1 that doesnt work and one that does. – Jason Mar 26 '20 at 17:06
  • You should avoid putting null values in your maps. All map implementations that came in Java 5 and later disallow null. And it seems that the language architects seem to think that the implementations of Java 4, which still allow null entries, were a mistake. Which would explain why the Stream API collector, while internally based on a 1.4 HashMap, won't allow null values. The behavior is true for Java 8 up to 14, so if you really need null as an option you either have to workaround or stick to a more traditional way of programming – Roland Kreuzer Mar 26 '20 at 17:50

1 Answers1

2

As the documentation says for Collectors::toMap

The returned Collector disallows null keys and values.

You do have a null value in "b"=null. And you are wrong about ... while putting values without manipulation. Of course you are "manipulating".

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • I could not get 'Of course you are "manipulating".' can you please explain this. – Prem Mar 26 '20 at 18:17
  • @Prem np, what do you think that `Entry::getValue` does? it is a shortcut for `x -> x.getValue()` where `x` is an `Entry`, right? – Eugene Mar 26 '20 at 18:38