2017-02-08 4 views
2

Der folgende Code kompiliert mit Javac und mit Eclipse 4.6.1/4.6, aber erzeugt einen Fehler in Eclipse 4.6.2:Eclipse oder Javac Bug; Lambda Typinferenz

package ecbug; 

import java.util.Collections; 
import java.util.Comparator; 
import java.util.List; 

public class Foo 
{ 
    class A 
    { 
     public int getStart() { return 0; } 
    } 

    void someMethod(List<A> toRemove) 
    { 
     Collections.sort(toRemove, Comparator.comparing(t -> -t.getStart())); 
    } 
} 

Eclipse-4.6.2 beklagt, unter -t.getStart(), dass Es gibt einen Type Mismatch: Konnte nicht von Int in Comparable < konvertieren? super Vergleichbar <? Super U > >.

Ich würde denken, dass die Argumente zu Comparator.comparing(...) ein Comparable<T> mit T = A sein sollten, mit funktionaler Methode compareTo die int zurückzugibt. Eclipse scheint zu glauben, dass die Lambda-Funktion Comparable < zurückgeben sollte? super Vergleichbar <? Super U > > jedoch.

ich stark ein Eclipse-Fehler vermuten, aber es gibt sicherlich Fälle, in denen von Eclipse die Sprachspezifikation und Javac nicht hat korrekt umgesetzt hat, so dass es zu fragen wert scheint: das ist ein Eclipse-Bug oder ein Javac Bug? Können Sprachanwälte auf die relevanten Teile der Sprachspezifikation hinweisen?

Möglicherweise verwandte Fragen, die in meinen Augen sind keine Duplikate:

Java 8 Stream flatMap and group by code compiler error - ähnliche Fehlermeldung, aber unklar, ob es genau das gleiche Problem ist; Die Antwort behauptet, dass es sich um einen Eclipse-Bug handelt, bietet aber keine Bug-Links oder JLS-Zitate; bezieht sich auf alte Eclipse-Version.

Why didn't this java 8 example using type inference compile in Eclipse? - ähnlich wie bei früheren

Java Stream collect after flatMap returns List<Object> instead of List<String> - auch hier kann ein anderes Problem sein; Kommentare beanspruchen Eclipse-Problem, rechtfertigen aber nicht durch Verweis auf JLS noch bieten sie einen Link zu einem Eclipse-Fehlerbericht.

+0

Ich habe in den letzten Jahren einige Fragen wie diese gesehen. Hast du wirklich gründlich gesucht? –

+0

@ T.J.Crowder ist es schwierig, die richtigen Suchbegriffe für etwas so spezifisch zu finden, aber ich habe eine Weile gesucht, ja. Es gibt einige Fragen, die einen verwandten Fehler anzeigen können (zB http://stackoverflow.com/questions/25853988/why-didnt-this-java-8-example-using-type-inference-compile-in-eclipse/25854229) aber ich kann keine finden, die sich auf die Sprachspezifikation beziehen, nach der ich hier gefragt habe. – davmac

+0

Kompiliert ohne Fehler für mich (Eclipse 4.6) –

Antwort

1

Ihre Erklärung trifft es nicht. Das Argument zu Comparator.comparing(...) (Version mit einem Argument) sollte nicht ein Comparable<T> sein, sondern ein Function<? super T,? extends U>, wohingegen T := A, aber U ist U extends Comparable<? super U>. So

, wenn Sie sagen

Eclipse-scheinen zu glauben, dass die Lambda-Funktion zurückkehren sollte Comparable<? super Comparable<? super U>>

Sie mit dem rechten Eclipse Erwartung ist in Bezug auf und Eclipse ist direkt in der Erwartung, dass auch.

Aber Ihre Funktion gibt einen int Wert, soll verglichen werden, und wenn Sie diesen Wert zu Integer Box, haben Sie einen Typ, der die erwartete U extends Comparable<? super U> Einschränkung erfüllt, als IntegerComparable<Integer> implementiert. Mit anderen Worten, U sollte als Integer gewertet werden, aber offensichtlich macht diese spezielle Eclipse-Version dies aufgrund des erforderlichen Boxens von int zu Integer nicht.


Als Seite beachten, wenn Sie eine int Eigenschaft vergleichen wollen, können Sie Comparator.comparingInt(...) trotzdem verwenden. Bei dieser Fabrik verhindert der zurückgegebene Komparator das Zusammenlegen von int bis Integer insgesamt.

Darüber hinaus sollten Sie eine Ganzzahl-Ordnung nicht durch Negation umkehren. Das Problem ist, dass
-Integer.MIN_VALUE == Integer.MIN_VALUE, als versucht, den kleinstmöglichen int Wert zu negieren, verursacht einen Überlauf Bewertung auf den kleinsten Wert int wieder, anstelle der größten. Die Verwendung der Negation zum Umkehren der Reihenfolge kann in vielen Situationen funktionieren, in einigen von ihnen kann es gerechtfertigt sein, da dieser spezielle Wert ausgeschlossen werden kann, jedoch schafft es eine schlechte Angewohnheit, die in einem Szenario, in dem die Situation auftreten kann, schrecklich zurückschlagen kann , natürlich nur selten und in der Regel nur bei den Kunden ...

Das richtige Idiom würde

Collections.sort(toRemove, Comparator.comparingInt(A::getStart).reversed()); 

, die durch Vertauschen der beiden Elemente arbeitet zu vergleichen, die in allen Szenarien gültig ist und keine Leistung Nachteile .

+0

Ja, ich wurde über den Argumenttyp 'Comparator.comparing (...)' durcheinander gebracht. Das klingt alles korrekt, aber ich warte auf eine Antwort auf den Eclipse-Fehler, bevor ich akzeptiere; Vielen Dank. Bezüglich der Verwendung von 'comparingInt' ist mir das bekannt, aber der ursprüngliche Code, von dem der Testfall abgeleitet ist, ist nicht mein Code. – davmac

+0

Es wurde als ein Duplikat eines anderen Bugs markiert - https://bugs.eclipse.org/bugs/show_bug.cgi?id=510111 - die Kommentare dort sind interessant, zB "... wo immer Fi θ erwähnt wird, führt javac zuerst aus eine nicht spezifizierte Substitution: Alle Inferenzvariablen, die bereits instanziiert sind, werden durch ihre jeweilige Instanziierung ersetzt. " "... JDK-8052325 schreibt vor, dass wir * keine * zusätzlichen Einschränkungen erzeugen. Das Fehlen solcher Einschränkungen ist der Grund, warum das Beispiel in diesem Fehler fehlschlägt." (https://bugs.openjdk.java.net/browse/JDK-8052325). Es scheint, dass es einige Spezifikationsausgaben gibt. Akzeptieren Sie Ihre Antwort trotzdem. – davmac