• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
  • Campbell Ritchie
  • Ron McLeod
  • Liutauras Vilda
  • Paul Clapham
  • paul wheaton
  • Tim Cooke
  • Devaka Cooray
  • Rob Spoor
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Tim Moores
  • Carey Brown
  • Mikalai Zaikin

Funny compile error using Collectors.maxBy and Comparator.naturalOrder() (and using lambdas)

Ranch Hand
Posts: 62
Eclipse IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, I am developing a small Maven-based project to provide some nice demos about the new Java 8 Stream API:


Normally I use Eclipse for my developments and everything works fine as expected. Today I tried to build my project outside Eclipse, using just Maven and JDK 8u112 (the latest at this moment). I got a "funny" compile error in one of my demos: MaxOriginDistanceByQuadrant.java

To be more clear about the problem, I tried to re-create a simpler/single source to reproduce the problem.
And it is:

A javac StreamProblem.java using directly the JDK 8u112 gives the following very "funny" error:

Note that this exact code perfectly compiles and works in Eclipse (the latest Neon.2 Release (4.6.2) Build id: 20161208-0600).

I noticed that I can solve the problem using the so called type witness on the naturalOrder():


However, there is still another funny thing. I have rewrote the code using method references only (no lambdas):

And it compiles and works on JDK 8u112 even without the type witness !

So I am wondering: is this a bug of JDK8? (I guess yes... and I hope it will be fixed!)
Is it related to maxBy? And/or lambdas?
Is the type witness on naturalOrder() the best solution at this moment?

By the way: if someone can give me some judgments on my project, I willingly appreciate.
Posts: 5458
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The problem me thinks, is that if you look at the API of collect, Collectors.groupingBy and Collectors.mapping, the class parameter <T> in the mapping is independant of the class parameter <T>  as used in the groupingBy. That is why java does not recognize the mehod getNum of obj2, ince it does not know what type obj2 is, This code works:

by helping java a little by revealing the type of obj2 that we are dealing with. That is why using 'MyObj::getNum' also suffices, and if you use Comparator<Double> it somehow also recognizes MyObj, although I do not completely understand what is happening in that case.
Posts: 161
  • Likes 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The reason why it works using method reference is obvious: method references include both the parameters and return types, so it gives the compiler much more information than needed. As Piet said, specifying the argument type for the mapper function is enough to make type inference work.

You have in fact many possible solutions:

1) using a method reference MyObj::getNum

2) specifying the parameter type for the mapper: (MyObj obj2) -> obj2.getNum()

3) using a parameterized method call: Collectors.maxBy(Comparator.<Double>naturalOrder())

4) Using a named Function:

5) Using an named Comparator for the downstream Collector:

Thee are probably many other possibilities to help the compiler inferring the Double type. The best one is obviously using method references.

This said, your very question was "is it a JDK bug?". The answer is no. It might be an Eclipse bug, depending on what were the requirements. Eclipse has its own compiler, and this compiler is (as you noted) not fully compatible with Java. So if the requirement for the Eclipse compiler was to be compatible with Java, it's an Eclipse bug. If the requirement was to be compatible with the Java 8 specification only, it's a feature.

Not everything is specified. For what is not specified, there is a "reference implementation". From Java Platform, Standard Edition 8 Reference Implementations :

The official Reference Implementations for Java SE 8 (JSR 337) are based solely upon open-source code available from the JDK 8 Project in the OpenJDK Community.

About one year ago, I submitted an issue to the Eclipse development team about the inverse problem: places were the Eclipse compiler was unable to infer types although Oracle JDK and OpenJDK could. The issue was rejected because they said it was not Eclipse which was not compatible, it was Oracle JDK that was not conform to the spec.

This obviously was not a big problem. An IDE with restrictions is fine. But an IDE that allows more that what the compiler used in production can accept is much more problematic. This shows that in any case, programmers should either avoid using Eclipse or compile with the JDK used in the build chain before submitting their work.

This, by the way, is not a problem specific to Eclipse. Programmers should develop with the same version of the JDK that the one used in production. Or at least, they should compile their code and run their tests locally using the correct version before submitting.
It is difficult to free fools from the chains they revere - Voltaire. tiny ad:
a bit of art, as a gift, that will fit in a stocking
    Bookmark Topic Watch Topic
  • New Topic