Warum dies nicht von Java 8 stream-Beispiel kompilieren?
Ich versuche, herauszufinden, warum dieser code nicht kompilieren auf JDK 1.8.0_45
:
public class Example<E extends Example<E>> {
public List<? extends Example<?>> toExamples(Collection<String> collection) {
return collection.stream()
.map(v -> lookup(v))
.collect(Collectors.toList());
}
public static <E extends Example<E>> E lookup(String value) {
return null;
}
}
Hinzufügen, eine scheinbar unnötige cast behoben werden:
public class Example<E extends Example<E>> {
public List<? extends Example<?>> toExamples(Collection<String> collection) {
return collection.stream()
.map(v -> (Example<?>) lookup(v))
.collect(Collectors.toList());
}
public static <E extends Example<E>> E lookup(String value) {
return null;
}
}
Hier ist die Fehlermeldung vom compiler:
Example.java:9: error: incompatible types: inference variable R has incompatible bounds
.collect(Collectors.toList());
^
equality constraints: List<Object>
upper bounds: List<? extends Example<?>>,Object
where R,A,T are type-variables:
R extends Object declared in method <R,A>collect(Collector<? super T,A,R>)
A extends Object declared in method <R,A>collect(Collector<? super T,A,R>)
T extends Object declared in interface Stream
Für einige Grund, der Rückgabetyp der lookup()
ist nicht korrekt abgeleitet, um etwas erweitern Example
.
- aus Neugier, habe es kompilieren auf alle früheren Versionen von Java 8? dieser Bericht scheint schrecklich relevant: bugs.openjdk.java.net/browse/JDK-8077304
- Was ist die genaue Fehlermeldung, die Sie bekommen?
- Sie können auch ändern, die Signatur-Suche:
public static <E extends Example<E>> Example<E> lookup(String value)
- Eine weitere Instanz der generischen Methoden, die den Anspruch auf Rückkehr, was der Anrufer will...
Du musst angemeldet sein, um einen Kommentar abzugeben.
Als Peter Lawrey hingewiesen,
? extends Example<?>
ist nicht kompatibel mitE extends Example<E>
. Dennoch, auch die Festsetzung der Signatur nicht der Typ-Inferenz, die hier arbeiten.Der Grund ist eine bekannte Einschränkung des Typ-Inferenz, da es nicht zurück-propagieren durch verkettete Methodenaufrufe. In anderen Worten, der return-Typ kann zum ableiten der Typen für die
collect(…)
Aufruf aber nicht für die vorhergehendenmap(…)
Aufruf. (siehe auch diese Antwort)Aber es funktioniert für verschachtelte - Methode aufrufen, so dass die folgenden umgeschrieben Methode kompiliert werden kann:
Immer noch, Sie haben zum Umdenken in der Semantik des Codes. Eine Methode, die Typ-parameter erscheint nur bei der return-Typ kann nicht richtig sein, da es impliziert, dass ", was der Anrufer Ersatz für diese Typ-parameter, den die Methode zurück, die richtige". Da die Implementierung der Methode nicht wissen, was der Anrufer meint, das ist unmöglich. Nur die Rückkehr
null
oder eine leere Liste wird korrekt funktionieren, das ist von wenig nutzen.Class<? extends Example<?>>
parameter in dertoExamples()
Methode, und eineClass<E>
parameter in derlookup()
Methode. Ich fürchte, ich vereinfachte das problem.Class<E>
die Sie Durchlaufen, die Typ-Inferenz sollte auch die Arbeit mit einer verketteten.map(…).collect(…)
Aufruf.Wenn Sie eine
?
es nicht gleich ein anderes?
d.h. der compiler sieht nichtals ein match für
da er nicht davon ausgehen, die zwei
?
sind die gleichen. Es könnte sein,Beim ausführen der Besetzung, Sie verdecken die Einschränkung, so kann es passen.
Meine Vermutung ist, dass der generische Typ definiert die statische Methode ist nicht dasselbe wie die generischen Typs in der Klasse definiert. Sie sollten in der Lage sein, um die
lookup
Methode nicht-statisch, so dass es passt die gleiche Art definiert in der Klasse generische Deklaration: