Kürzlich lese ich den Quellcode von Spring Framework. Etwas, das ich nicht verstehen kann, geht hier:
public Member getMember() {
// NOTE: no ternary expression to retain JDK <8 compatibility even when using
// the JDK 8 compiler (potentially selecting java.lang.reflect.Executable
// as common type, with that new base class not available on older JDKs)
if (this.method != null) {
return this.method;
}
else {
return this.constructor;
}
}
Diese Methode ist Mitglied der Klasse org.springframework.core.MethodParameter
. Der Code ist leicht zu verstehen, während die Kommentare schwierig sind.
ANMERKUNG: Kein ternärer Ausdruck, um die JDK <8-Kompatibilität beizubehalten, selbst wenn der JDK 8-Compiler verwendet wird (möglicherweise
java.lang.reflect.Executable
als allgemeiner Typ ausgewählt, da diese neue Basisklasse bei älteren JDKs nicht verfügbar ist)
Was ist der Unterschied zwischen der Verwendung des ternären Ausdrucks und der Verwendung des if...else...
Konstrukts in diesem Zusammenhang?
quelle
Dies wurde in einem ziemlich alten Commit am 3. Mai 2013 eingeführt, fast ein Jahr vor der offiziellen Veröffentlichung von JDK-8. Der Compiler befand sich zu dieser Zeit in einer intensiven Entwicklung, so dass solche Kompatibilitätsprobleme auftreten konnten. Ich denke, das Spring-Team hat gerade den JDK-8-Build getestet und versucht, Probleme zu beheben, obwohl es sich tatsächlich um Compiler-Probleme handelt. Mit der offiziellen Veröffentlichung von JDK-8 wurde dies irrelevant. Jetzt funktioniert der ternäre Operator in diesem Code wie erwartet
Executable
einwandfrei (es ist kein Verweis auf die Klasse in der kompilierten .class-Datei vorhanden).Derzeit erscheinen ähnliche Dinge in JDK-9: Ein Teil des Codes, der in JDK-8 gut kompiliert werden kann, ist mit JDK-9 javac fehlgeschlagen. Ich denke, die meisten dieser Probleme werden bis zur Veröffentlichung behoben sein.
quelle
Executable
, gegen einen Aspekt der Spezifikation? Oder hat Oracle nur erkannt, dass sie dieses Verhalten so ändern können, dass es immer noch der Spezifikation entspricht und ohne die Abwärtskompatibilität zu beeinträchtigen?Executable
dazwischen zu tippen. In Java-8 hat sich das Konzept der Inferenz von Ausdruckstypen drastisch geändert, und dieser Teil wurde vollständig neu geschrieben. Daher ist es nicht so überraschend, dass frühe Implementierungen Fehler aufwiesen.Der Hauptunterschied besteht darin, dass ein
if
else
Block eine Anweisung ist, während der ternäre Block ( in Java häufiger als bedingter Operator bezeichnet) ein Ausdruck ist .Eine Anweisung kann
return
auf einigen Steuerpfaden Dinge wie den Aufrufer tun . Ein Ausdruck kann in einer Aufgabe verwendet werden:int n = condition ? 3 : 2;
Daher müssen die beiden Ausdrücke im Ternär nach der Bedingung auf denselben Typ erzwungen werden können. Dies kann in Java einige seltsame Effekte verursachen, insbesondere beim automatischen Boxen und beim automatischen Referenzcasting. Darauf bezieht sich der Kommentar in Ihrem veröffentlichten Code. Der Zwang der Ausdrücke in Ihrem Fall wäre ein
java.lang.reflect.Executable
Typ (da dies der spezialisierteste Typ ist ), der in älteren Java-Versionen nicht vorhanden ist.Stilistisch sollten Sie einen
if
else
Block verwenden, wenn der Code anweisungsähnlich ist, und einen ternären, wenn er ausdrucksähnlich ist.Natürlich können Sie einen
if
else
Block wie einen Ausdruck verhalten lassen, wenn Sie eine Lambda-Funktion verwenden.quelle
Der Rückgabewerttyp in einem ternären Ausdruck wird von übergeordneten Klassen beeinflusst, die sich wie in Java 8 beschrieben geändert haben.
Schwer zu verstehen, warum eine Besetzung nicht geschrieben werden konnte.
quelle