Check whether a map contains not null values for only a set of keys

Viewed 40

I have a map as below

Map<String, String> myMap = new HashMap<>();
myMap.put("a", "Something");
myMap.put("b", null);
myMap.put("c", "more");

and a list,

List<String> myList = Arrays.asList("a","b");

I want to check, whether all the values in myMap with keys in myList are null

I have created a method as follows and it works fine. I wanted to check whether we can achieve the same in one line of code using stream

myMap.values().removeIf(Objects::isNull);

Map<String, String> resultMap = myList.stream().filter(myMap::containsKey).collect(Collectors.toMap(Function.identity(), myMap::get));
if(!resultMap.isEmpty()){
// Atleast one not null value is present in myMap with key in myList
}
3 Answers

Sure, simply check if all elements in the list match a non-null value from the map:

myList.stream().allMatch(x -> myMap.containsKey(x) && myMap.get(x) == null);
// or (more overhead, but you might prefer its expressivness):
myList.stream()
    .filter(myMap::containsKey)
    .map(myMap::get)
    .allMatch(Objects::isNull);

Or, if you consider "missing keys" to be equivalent to "having null":

myList.stream().map(myMap::get).allMatch(Objects:isNull);

Map.get specifies that keys that aren't present return null. So you can filter out keys mapped to null or not mapped at all with just one null check.

Map<String, String> resultMap = myList.stream()
    .filter(key -> myMap.get(key) != null)
    .collect(Collectors.toMap(Function.identity(), myMap::get));

If you don't need a resultMap it's even shorter with anyMatch

myList.stream().allMatch(key -> myMap.get(key) != null)

Unlike myMap.values().removeIf(Objects::isNull) this will not modify the original map.

So, you've removed the entries having null values with this line:

myMap.values().removeIf(Objects::isNull);

Fine, since keeping null-references in the collections an antipattern because these elements can't provide any useful information. So I consider this was your intention unrelated to checking if all the string in myList were associated with null (or not present).

Now to check whether myMap contain any of the elements from myList (which would automatically imply that the value mapped to such element is non-null) you can create a stream over the contents of myList and check each element against the key-set of myMap:

boolean hasNonNullValue = myList.stream().anyMatch(myMap.keySet()::contains);

I suspect you might to perform some actions with such keys (if any). If so, then instead of performing a check provided above would make sense to generate a list of these keys:

List<String> keysToExamine = myList.stream()
    .filter(myMap.keySet()::contains)
    .toList(); // for JDK versions earlier then 16 use .collect(Collectors.toList()) instead of toList()

Note: check elements of the list against the key-set, not the opposite, otherwise you might cause performance degradation.

Related