Just when I think I am a super-expert in Java generics, a simple thing throws me for a loop. I'm using Java 8 in Eclipse 4.6.3.
Let's say I make an enum of orderings for FooBar
, and I want each enum value to give me a Comparator<? extends FooBar>
appropriate for the ordering:
public enum FooBarOrdering {
BY_FOO_ASCENDING, BY_FOO_DESCENDING;
public Comparator<? extends FooBar> getComparator() {
switch (this) {
case BY_FOO_ASCENDING:
return Comparator.comparing(fooBar -> fooBar.getFoo());
//…
}
}
}
Yay, that works for a charm, just like I thought it would! (Yes, here I could use a method reference, but ignore that for now ---that's irrelevant to the issue here.) Now to add the comparator for BY_FOO_DESCENDING
.
Hmmm... first of all, Eclipse's auto-complete doesn't seem to work on the returned comparator. Never mind --- I know how to read Javadocs, so I add this:
case BY_FOO_DESCENDING:
return Comparator.comparing(fooBar -> fooBar.getFoo()).reversed();
Eclipse now tells me: Cannot infer type argument(s) for <T, U> comparing(Function<? super T,? extends U>)
And also: The method getFoo() is undefined for the type Object
Now why did getFoo()
work just fine in the first example, but did not work when I call a method from the returned Comparator value? If Eclipse/Java knew that there was a FooBar
with a getFoo()
method in the earlier code, why did adding a reversed()
method on the return value change anything?
And here's how silly it gets: look at the source code for Comparator.reversed())
; it simply returns Collections.reverseOrder(this)
. So if I change the code to the following, it works fine:
case BY_FOO_DESCENDING:
return Collections.reverseOrder(Comparator.comparing(fooBar -> fooBar.getFoo()));
So is this an Eclipse bug? Or is Java still just a bit dumb when it comes to generics? Or am I missing something?
I would really like to use Comparator.reversed()
, so if you tell me some cast or <blah>
I can add to the expression to make it work, that would be nice. Thanks.