yep, the inference is not smart enough. So the way to fix the code is either to explicitly specify the type arguments var rs1 = x.entrySet().stream().sorted( Map.Entry.<String, Long>comparingByValue().reversed() );
or to store the result of comparingByValue() in a variable (so it's a poly expression) Comparator<Map.Entry<String, Long>> comparator = Map.Entry.comparingByValue(); var rs1 = x.entrySet().stream().sorted(comparator.reversed()); regards, Rémi ----- Mail original ----- > De: "Tagir Valeev" <amae...@gmail.com> > À: "Attila Szegedi" <szege...@gmail.com> > Cc: "core-libs-dev" <core-libs-dev@openjdk.java.net> > Envoyé: Mardi 9 Juin 2020 09:05:42 > Objet: Re: Comparator.reversed() type inference issue > Hello! > > This is more related to Java language specification and implementation > than to core libraries, so compiler-dev is a more relevant mailing > list. The current behavior perfectly follows the specification (JLS, > 15.12): > > A method invocation expression is a poly expression if all of the > following are true: > - The invocation appears in an assignment context or an invocation > context (§5.2, §5.3). (1) > - If the invocation is qualified (that is, any form of > MethodInvocation except for the first), then the invocation elides > TypeArguments to the left of the Identifier. (2) > - The method to be invoked, as determined by the following > subsections, is generic (§8.4.4) and has a return type that mentions > at least one of the method's type parameters. (3) > > If method invocation is a qualifier (in your case > Map.Entry.comparingByValue() is a qualifier of reversed() call) then > the context is neither assignment, nor invocation, hence (1) is not > satisfied, hence it's a standalone expression, hence its type is > determined solely by expression content. That's why to determine the > type of Map.Entry.comparingByValue() we cannot look outside and must > consider only the expression content. So its type is determined to be > Comparator<Entry<Object,V#2>> (V#2 extends Comparable<? super V#2>), > as we don't have any other information. The reversed() call is also > standalone, as the reversed() method is not generic, so (3) is not > satisfied. Thus its type is just the same as its qualifier type. > > People asked many times whether it's possible to make this code > working without explicit type arguments. However, it's not just a > trivial patch to the compiler and the spec. It's huge amount of work > that may introduce tons of bugs, compiler crashes (I would expect > StackOverflowError appear often during the compilation), compiler > performance regression, and so on. Also, loads of inconsistencies > between compiler and IDE behavior. I personally don't work on Java > compiler, but I sometimes investigate bugs inside the IntelliJ IDEA > type inference procedure. Believe me, it's already insanely complex, > and the fact that at very least we can exclude qualifiers from the > equation is really relieving. So while I cannot say for the whole > OpenJDK team, I hardly believe this could be implemented any time > soon. > > With best regards, > Tagir Valeev. > > On Sun, Jun 7, 2020 at 7:34 PM Attila Szegedi <szege...@gmail.com> wrote: >> >> Hi folks, >> >> I'm teaching Java lately, and while teaching streams I use that good old >> chestnut, the word count example. I'm baffled with some type inference woes, >> though… trying to specify a reverse comparator using Comparator.reversed() >> makes javac sad, e.g. this does not compile[1]: >> >> Map<String, Long> x = someMap(); >> >> var rs1 = x.entrySet().stream().sorted( >> Map.Entry.comparingByValue().reversed() >> ); >> >> On the other hand, using Collections.reverseOrder does compile: >> >> var rs2 = x.entrySet().stream().sorted( >> Collections.reverseOrder( >> Map.Entry.comparingByValue() >> ) >> ); >> >> Happens on both Java 11 and 14. It’s just baffling because based on type >> signatures, it seems reasonable the first form should work as well. >> >> Thanks for any enlightenment! >> >> Attila. >> >> --- >> [1] -Xdiags:verbose on Java 14 says: >> error: no suitable method found for sorted(Comparator<Entry<Object,V#1>>) >> var rs1 = x.entrySet().stream().sorted( >> >> method Stream.sorted() is not applicable >> (actual and formal argument lists differ in length) >> method Stream.sorted(Comparator<? super Entry<String,Long>>) is not >> applicable >> (argument mismatch; Comparator<Entry<Object,V#2>> cannot be converted to >> Comparator<? super Entry<String,Long>>) >> where V#1,V#2 are type-variables: >> V#1 extends Comparable<? super V#1> > > V#2 extends Comparable<? super V#2>