3

I would like to ensure that a Map being passed as an argument to a method doesn't include null keys. One would assume that the following would do:

if ( map.containsKey(null) ) …

but that will break if the method is passed something like a TreeMap, which per the general Java Map contract is free to reject null keys with a NPE.

Do we have a sensible way to test for null keys while accepting any Map implementation?

A'B
  • 535
  • 3
  • 9

3 Answers3

5
boolean hasAnyNull = yourMap.keySet()
      .stream()
      .anyMatch(Objects::isNull);
Eugene
  • 117,005
  • 15
  • 201
  • 306
  • This may have to loop over all keys, which is usually exactly what you want to avoid when you use a `Map`. – Joachim Sauer Sep 11 '18 at 12:18
  • @JoachimSauer exactly right, but looping over a map might be cheaper than building an `Exception` with the entire stacktrace. – Eugene Sep 11 '18 at 12:19
1
boolean hasNullKey(Map<?,?> map) {
  try {
    return map.containsKey(null);
  } catch (NullPointerException e) {
    return false;
  }
}

Note that this also returns false when map itself is null, which may or may not be desired.

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
  • System.out.println(hasNullKey(null)); this statement also print false. – gifpif Sep 11 '18 at 12:13
  • @JoachimSauer exception to control flow... I don't know, not for my taste – Eugene Sep 11 '18 at 12:15
  • @gifpif: Yes, which is exactly what my note says. – Joachim Sauer Sep 11 '18 at 12:16
  • 1
    @Eugene: it's not nice, but it's not O(n). I think the question itself already contains problematic assumptions Why is the presence of a `null` key relevant, yet the code accepts maps that can't have `null` keys? Seems like something that needs to be fixed with a more stringent specification. – Joachim Sauer Sep 11 '18 at 12:18
  • @JoachimSauer the method is part of a library public API: I have no control on the actual implementation of the Map being passed as argument, yet I want to make sure keys are not null – A'B Sep 11 '18 at 12:26
  • @A'B: then why don't you do what `containsKey` does? Define your method to (potentially) throw an NPE when the map contains `null` (or if the `Map` *doesn't* accept `null`, depending on which way around you want to handle it). – Joachim Sauer Sep 11 '18 at 12:27
  • @JoachimSauer I'm indeed doing that, but the potentially offending processes are some steps away from the public API call: I'm just trying to trap the issue as soon as possible in order to provide clearer error messages and I was hoping for a one-liner ;-) – A'B Sep 11 '18 at 12:32
  • 1
    @A'B: ok, so *what* exactly is the "error condition" here? `null` in the map or a map implementation that doesn't allow ` null`? If it's the former, you could run your code, catch the inevitable exception and *then* run some (potentially costly) checks to see if it the exception is caused by a known problem such as passing a broken parameter to your code and provide an appropriate error message. – Joachim Sauer Sep 11 '18 at 12:34
  • @JoachimSauer `null` in the map. Nice hint… – A'B Sep 11 '18 at 13:13
0

Use instanceof to find its a TreeMap

boolean hasNullKey(Map<?,?> map) {
    return map instanceof TreeMap ? false :map.containsKey(null);
}
gifpif
  • 4,507
  • 4
  • 31
  • 45
  • 1
    JavaDoc [TreeMap.put](https://docs.oracle.com/javase/10/docs/api/java/util/TreeMap.html#put(K,V)) says: "_... throws NullPointerException - if the specified key is null and this map uses natural ordering, or its comparator does not permit null keys_" - A `TreeMap` may contain null-keys if it's comparator can handle them. – LuCio Sep 11 '18 at 12:35
  • @LuCio *generally* every `Map` since `HashMap` prohibits nulls; this is the case for `CHM/Map::of` etc; having that null is just a pain the soft side – Eugene Sep 11 '18 at 12:37
  • And what about other maps which do not permit `null` like `EnumMap`? – LuCio Sep 11 '18 at 12:37