The Java Language Specification writes:
The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of generics into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.
That leaves the other two. As ScheduledFuture
only uses its type parameter in a method return type, ScheduledFuture<?>
(which is the same as ScheduledFuture<? extends Object>
) is equivalent to ScheduledFuture<Object>
to calling code.
However, code that actually creates an instance of a ScheduledFuture needs to work with a subclass of ScheduledFuture, and may care a great deal about the type parameter that subclass implements ScheduledFuture with.
When declaring a method that returns a ScheduledFuture, you will therefore want to use the type ScheduledFuture<?>
as that signature is easier to implement for the producer of the ScheduledFuture, but equally useful to its consumer. (This is simply a special case of the PECS rule.)