Skip to content
Advertisement

Wildcard generic type of predicate in stream not applicable

I have a trimmed down version of my code to illustrate the issue.

Here’s the compilation error I’m getting:

The method anyMatch(Predicate<? super capture#26-of ?>) in the type Stream<capture#26-of ?> is not applicable for the arguments (Predicate<Map<?,?>>)

My code:

private void func(Object o) {
    Predicate<Map<?, ?>> pred = m -> true;
    if (o instanceof Map && pred.test((Map<?, ?>) o)) {
        // ...pred.test is OK
    } else if (o instanceof Collection && ((Collection<?>) o).stream().filter(i -> i instanceof Map).anyMatch(pred)) {
        // ...anyMatch here gives the above error
    }
}

How would you fix the code to remove the error? Thank you!

Advertisement

Answer

The fact that you have applied instanceof check in the filter() doesn’t change the type of the stream, it remains to be Stream<Object>.

filter() operation is meant for discarding elements from the stream, not for modifying the elements, therefore it’s not capable of changing the type of the stream.

To perform modifications, you need to apply map() operation and either use conversion via type cast or method Class.cast():

.<Map<?,?>>map(Map.class::cast)

or

.map(i -> (Map<?, ?>) i)

Alternatively, you can leverage Java 16 Pattern matching for instanceof combining both filter and map in one step by making use of mapMulty() which was also introduced with Java 16:

((Collection<?>) o).stream()
    .<Map<?,?>>mapMulti((i, consumer) -> {
        if (i instanceof Map m) consumer.accept(m);
    })
    .anyMatch(pred)

Note

It is worth to point out that the whole problem derived from the way the method is designed. By making it accept an argument of type java.lang.Object you’re forced to operate via type-checking and casting.

A more maintainable approach would to try to leverage generic types, potentially it might lead to splitting this method into several methods (or introducing a few auxiliary methods). But if it would be the case it’s not a disadvantage, leaner method easier to digest, and it’s less error-prone.

Also, worth reminding that if you have multiple pieces of functionality performing unrelated things packed together, it’s probably a violation of the first principle of SOLID.

As the sidenote, from the perspective of clean-coding I would not advise placing a stream into the if-statement, especially containing multiple operation. Alternative: extract this logic, give it a name, explaining what it does, and refer to it via method call or Predicate

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement