Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does <? super Void> mean?

Tags:

java

generics

I have encountered this class in code that I'm maintaining:

new GenericFutureListener<Future<? super Void>>() {...}

I'm having a really hard time understanding what this means. A Future containing a type that is either Void or its superclass - Object. So why not just write Future<Object>?

like image 620
JamMaster Avatar asked Jul 10 '18 07:07

JamMaster


People also ask

What is <? Super T mean?

super T denotes an unknown type that is a supertype of T (or T itself; remember that the supertype relation is reflexive). It is the dual of the bounded wildcards we've been using, where we use ? extends T to denote an unknown type that is a subtype of T .

Do generics prevent type cast errors?

Implementing generics into your code can greatly improve its overall quality by preventing unprecedented runtime errors involving data types and typecasting.


3 Answers

Something nobody else pointed out: it's Netty and if you look at https://netty.io/4.0/api/io/netty/util/concurrent/class-use/Future.html you'll see there are some methods taking just this type in the library, e.g. ChannelPromise.addListener(GenericFutureListener<? extends Future<? super java.lang.Void>> listener). And these methods have this signature because of the generic case: Future.addListener(GenericFutureListener<? extends Future<? super V>> listener). ChannelPromise merely extends Future<Void>.

The generic case makes sense because 1. if you have a FutureListener<Future<Object>>, it can handle any Object value when a future completes; 2. since a V is an Object it can handle V. Thus it can listen to a Future<V>. Obviously the same holds for any supertype of V instead of Object.

Of course, these signatures would be much simpler if Java had declaration-site variance, but it doesn't and probably won't any time soon.

like image 51
Alexey Romanov Avatar answered Oct 17 '22 20:10

Alexey Romanov


It looks like this is being created to conform to some generic type like GenericFutureListener<Future<? super T>>, which is not flexible enough to allow for GenericFutureListener<Future<Void>> alone.

For instance if you have something like this:

class GenericFutureListener<T> {}

public static <T> void m(GenericFutureListener<Future<? super T>> p) {
    ...
}
m(new GenericFutureListener<Future<? super Void>>() {}); // works,
m(new GenericFutureListener<Future<Void>>() {}); // does not work

Passing in just a GenericFutureListener<Future<Void>> is not allowed.

like image 23
Jorn Vernee Avatar answered Oct 17 '22 20:10

Jorn Vernee


As you've noted, this Future<? super Void> can only be a void future, or Object future.

But:

So why not just write Future?

The intention of the developer was almost certainly to limit "listeners" to void actions. But if one allowed Future<Object>, then any other type could be used as the Future's value, because a Future<Object> could hold a String (or any other type) result.

java.lang.Void being a final class, it doesn't allow any child classes, which effectively almost completely limits it to void actions (unless one has practical value in calling new Object() when setting the result of the future)

like image 2
ernest_k Avatar answered Oct 17 '22 20:10

ernest_k