Eugene
Eugene

Reputation: 120848

generics: filter a Collection<T> but at the same time bound it to RandomAccess

Suppose I want to have such a method:

private static <T> Collection<T> filter(Collection<T> initial, Predicate<T> predicate){
    //....
}

This is trivial.

But, for some reason, I want to take as input not a simple Collection, but one that implements RandomAccess. So I change the definition to:

 private static <T, M extends Collection<T> & RandomAccess> Collection<T> filter(M initial, Predicate<T> predicate){
    return initial.stream()
                  .filter(predicate)
                  .collect(Collectors.toList());
}

this works on the declaration, but it would fail for callers. That is:

filter(List.of(1,2,3), x -> x > 1); // fails

What I find a bit awkward is that the compilation (and thus the resolution of T) works if I remove the & RandomAccess part:

private static <T, M extends Collection<T>> Collection<T> filter(M initial, Predicate<T> predicate){
    ....
} 

I would understand if the failure would occur if RandomAccess would take a type parameter. But it does not, so (at least in my understanding) it should not influence the resolution of T.

Is there a way to have such a compile time constraint at all?

Upvotes: 1

Views: 43

Answers (1)

ernest_k
ernest_k

Reputation: 45309

I would understand if the failure would occur if RandomAccess would take a type parameter. But it does not, so (at least in my understanding) it should not influence the resolution of T.

It does not. The problem with filter(List.of(1,2,3), x -> x > 1); is that the static type of the expression List.of(1,2,3) is not a subtype of RandomAccess, and that's rejected because it does not meet the extends RandomAccess constraint.

Both of the following compile with no problem, with the inference of T remaining unaffected

filter(new ArrayList<>(List.of(1, 2, 3)), x -> x > 1);
filter(new ArrayList<>(List.of("a", "b", "c")), x -> x.length() > 1);

Simply because ArrayList is both a Collection and RandomAccess subtype. I guess, however, that depending on your compiler implementation, you have one of many flavors of unhelpful error messages (like The method filter(M, Predicate<T>) in the type Main is not applicable for the arguments (List<Integer>) on filter(...) and Type mismatch: cannot convert from List<Integer> to M on List.of(...) in Eclipse)

Upvotes: 1

Related Questions