If I have a generic <T2 extends T1>, does the compiler infer T1 super T2?
I have a more complex collection, which I reduced to the MWE below. The collection shall be mergeable with any such collection with elements of any subtype.
Now I'm wondering, why the call to forEach in merge is not accepted. It fails with
java.util.function.Consumer<java.util.Optional> cannot be converted to java.util.function.Consumer<java.util.Optional<? super T2>>
I've depicted the type relationships in the diagram below. In merge, T2 extends T1. The call to forEach is applied on the other object, hence the T1 of this becomes the ? of other.forEach and the T2 of this.merge is the T1 of other. Hence, this' T1 should be accepted as super of other's T1.
I also tried public void merge(Group<? extends T> other) with the same result. And public void merge(Group<T> other) does not accept such collections with elements of any subtype of T1.
MWE:
class Group<T1> {
public <T2 extends T1> void merge(Group<T2> other) {
Consumer<Optional<T1>> task = t -> t.ifPresentOrElse(this::foo, this::bar);
other.forEach(task);
}
public Collection<Optional<T1>> values() {
return List.of();
}
public void forEach(Consumer<Optional<? super T1>> consumer) {
values().forEach(consumer);
}
private void foo(T1 t) {}
private void bar() {}
}
Relationships:
this.T1 -becomes-> other.forEach.?
^ |
| super
extends |
| v
this.merge.T2 -is-> other.T1
CodePudding user response:
If you have a Consumer<Optional<? super T1>> consumer then you can pass it (to the accept(T) method) an Optional<Object> because Object is a supertype of T1.
On the other hand, you cannot pass an Optional<Object> to Consumer<Optional<T1>> task because T1 might not be Object.
So you cannot assign the Consumer<Optional<T1>> task to the Consumer<Optional<? super T1>> consumer to prevent your consumer from being passed objects of types it does not expect.
