It sugests using UnaryFunction<?> because you only use one of the variables, not both. Function<?, ?> implies that you’ll be using 2 variables for your function.
Sure, I understand that in this specific little toy example, this would just happen to work. But that’s not the point. ? is not covariant with ?.
The type Function<?, ?> says “I will accept any object and I will return you something, and you don’t know what type it has”.
UnaryOperator<?> says “I will accept any object and return you something of the same type.”
Those do not mean the same thing. To better illustrate my point, consider the following code, which does not compile:
import java.util.function.Function;
import java.util.function.UnaryOperator;
public class FunTypes {
public static final Function<?, ?> NEW_OBJECT = anything -> new Object();
public static UnaryOperator<?> asUnaryOperator() {
return t -> NEW_OBJECT.apply(t);
}
}
The compiler rejects this because the ? that is accepted by apply() is not the same ? that is returned.
Here’s another example that might be more compelling. concreteAsUnary() compiles just fine, but wildcardAsUnary() does not compile due to “Incompatible equality constraint: capture of ? and capture of ?”
import java.util.function.Function;
import java.util.function.UnaryOperator;
public class FunTypes {
public static final Function<?, ?> WILDCARDS = anything -> anything;
public static final Function<Object, Object> CONCRETE = anything -> anything;
public static UnaryOperator<?> wildcardAsUnary() {
return asUnaryOperator(WILDCARDS);
}
public static UnaryOperator<Object> concreteAsUnary() {
return asUnaryOperator(CONCRETE);
}
public static <T> UnaryOperator<T> asUnaryOperator(Function<T, T> f) {
return f::apply;
}
}