Reputation: 1348
I'm having trouble understanding the method signature:
static <T,U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T,? extends U> keyExtractor)
Getting confused by super
, extends
, wild card (?
) and multiple angle brackets. Please don't get me wrong, I understand basic generics. It is the higher constructs being used here which confuse me.
Upvotes: 2
Views: 690
Reputation: 5285
So the basic form of the function is
static <T, U> Comparator<T> comparing(Function<T, U> extractor)
We'll deal with the finer-grained modifications later. What the above is saying is, in order:
static
: straightforward, importantly though, this means the function is not bound to the type of its object instance, so even though Comparator
is defined and instantiated as Comparator<T>
we still write T
in...
<T, U>
: this tells us the function itself is generic over the types T
and U
. This is just like when you write class <T, U> MyClass
- you're saying that these types will define the behavior of the rest of the function. In this case, these types define the parameters of the function, and will be inferred based on what parameter we provide. If we give a Function<Foo,Bar>
to comparing()
then the compiler will infer T = Foo.class
and U = Bar.class
.
Comparator<T>
: the return type, a thing capable of comparing T
; fairly straightforward.
Function<T, U>
: a mapping from T
to U
; fairly straightforward.
Now for the rest:
<T, U>
is really <T,U extends Comparable<? super U>>
, which means T
is whatever and U
needs to extend Comparable
(i.e. be comparable) even if it's really just comparable based on its super type. For example, I may have Bar extends Foo
where Foo implements Comparable
; I can still compare objects of type Bar
by treating them as Foo
. Here's a concrete example:
MyBigInt implements Comparable<MyBigInt>
. Assume we've implemented the Comparable
interface and our class is correctly compared based on its integer value. MyBigColorfulInt extends MyBigInt
, which adds some silly non-integer functionality - importantly, it does not implement Comparable<MyBigColorfulInt>
, but as a subclass of MyBigInt
it does (implicitly) implement Comparable<MyBigInt>
.<T, U extends Comparable<? super U>
: say our type T
contains within it a field of type MyBigColorfulInt
, and I would like to compare objects of type T
based on their MyBigColorfulInt
member (this is U
). IF the signature was U extends Comparable<U>
we would be out of luck: MyBigColorfulInt
does not implement Comparable<MyBigColorfulInt>
. However, we really want to compare MyBigColorfulInt
's as MyBigInt
's, anyway. U extends Comparable<? super U>>
lets us do this for free, because it lets U
be compared based on its super class. If not for this, the best we could do is cast each MyBigColorfulInt
to MyBigInt
before comparing, which is not great.Function<T, U>
is really Function<? super T,? extends U>
, so one at a time:
<? super T>
similar to the point above about U
, all this really means is that we have to be able to extract something to compare (U
) from T
, and it's OK if the thing we're extracting really comes from T
's super class.
<? extends U>
also similar (in a different way) to the point above: our function needs to extract a thing of type U
to be compared, but it's alright if the thing we're extracting is a descendant of U
, as long as it can be used as a U
for the basis of our comparison.
Upvotes: 8