3yakuya
3yakuya

Reputation: 2662

Check for null entries in Java Map<T, ? extends E>

I have a Map<String, ? extends Collection<SomeClass>>. I would like to ensure that there are no entries where collection's size is 0. Therefore I tried myMap.values().stream().map(Collection::size).allMatch(size -> size > 0). However, as it turned out, myMap contains null entries.

I wanted to check if my map contains null entries: resourceMap.values().stream().noneMatch(null) but I got an Exception java.util.Objects.requireNonNull.

I decided to do it in a relatively old fashioned way, with a for-in loop for (Map.Entry<String, ? extends Collection> entry : myMap) However, I got a compilation error telling me that foreach is not applicable to my Map.

What is an elegant way to check if all entries in my map are not null and with size > 0?

Upvotes: 1

Views: 807

Answers (2)

Holger
Holger

Reputation: 298143

You can just check for nulls using myMap.values().contains(null)—no Stream API required.

If your map was consistently using List or Set, you could also check for empty values with myMap.values().contains(Collections.emptySet()) or myMap.values().contains(Collections.emptyList()), but since there is no general equality contract between arbitrary collections, that doesn’t work for your Map<String, ? extends Collection<SomeClass>>.

So for this specific test, you could use

boolean violations = myMap.values().contains(null)
                  || myMap.values().stream().anyMatch(Collection::isEmpty);

or

boolean violations = myMap.values().stream().anyMatch(col -> col==null || col.isEmpty());

When you want to iterate with a for loop, you have to specify a Collection view over the Map, e.g.

Map<String, ? extends Collection<SomeClass>> myMap;
…
for (Map.Entry<String, ? extends Collection<?>> entry: myMap.entrySet())
    // loop body

or, much better for this use case

for(Collection<?> value: myMap.values())
    if(value == null || value.isEmpty())
        // violation detected, perform your action

Upvotes: 6

Grzegorz Piwowarek
Grzegorz Piwowarek

Reputation: 13773

If you have a look at the actual method signature:

boolean noneMatch(Predicate<? super T> predicate)

You will see that noneMatch(null) accepts a Predicate instance and not an actual value. Null predicates are forbidden here.

Try:

boolean result = resourceMap.values().stream()
  .noneMatch(Objects::isNull)

You can merge those two into one chain:

myMap.values().stream()
  .allMatch(col -> col != null && col.size() > 0);

Upvotes: 3

Related Questions