Opérateur ternaire Java vs if / else in
récemment je suis en train de lire le code source de Spring Framework. Quelque chose que je ne peux pas comprendre va ici:
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;
}
}
cette méthode appartient à la classe org.springframework.core.MethodParameter
. Le code est facile à comprendre tandis que les commentaires sont durs.
NOTE: Pas d'expression ternaire pour conserver la compatibilité JDK <8 même en utilisant le compilateur JDK 8 (en sélectionnant potentiellement
java.lang.reflect.Executable
comme type commun, avec cette nouvelle classe de base non disponible sur âgées Jdk)
Quelle est la différence entre utiliser l'expression ternaire et utiliser la construction if...else...
dans ce contexte?
4 réponses
quand on pense au type des opérandes, le problème devient plus apparent:
this.method != null ? this.method : this.constructor
a comme type le type le plus spécialisé commun des deux opérandes, c'est-à-dire le type le plus spécialisé commun aux deux this.method
et this.constructor
.
en Java 7 c'est java.lang.reflect.Member
, cependant la bibliothèque de classe Java 8 introduit un nouveau type java.lang.reflect.Executable
qui est plus spécialisé que le générique Member
. Ainsi, avec une bibliothèque de classe Java 8, le type de résultat de l'expression ternaire est Executable
plutôt que Member
.
certaines versions (pré-release) du compilateur Java 8 semblent avoir produit une référence explicite à Executable
dans le code généré lors de la compilation de l'opérateur ternaire. Cela déclencherait une charge de classe, et donc à son tour un ClassNotFoundException
à l'exécution avec une bibliothèque de classe < JDK 8, parce que Executable
n'existe que pour JDK ≥ 8.
comme L'a noté Tagir Valeev dans cette réponse , il s'agit en fait d'un bug dans les versions pré-publication de JDK 8 et a depuis été corrigé, de sorte que la solution de contournement if-else
et le commentaire explicatif sont désormais obsolètes.
note supplémentaire: on pourrait conclure que ce bogue de compilateur était présent avant Java 8. Cependant, le code octet généré pour le ternaire par OpenJDK 7 est le même que le code octet généré par OpenJDK 8. En fait, le type d'expression passe complètement inaperçu à l'exécution, le code n'est en réalité que test, branche, charge, retour sans aucun contrôle supplémentaire en cours. Ainsi, soyez assurés que ce n'est plus un problème (désormais) et semble en effet avoir été un problème temporaire lors du développement de Java 8.
cela a été introduit dans tout à fait vieux commit le 3 mai 2013, presque un an avant la sortie officielle de JDK-8. Le compilateur était alors en cours de développement, de sorte que de tels problèmes de compatibilité pouvaient se produire. Je suppose que L'équipe de Spring vient de tester la construction JDK-8 et a essayé de résoudre des problèmes, même s'ils sont en fait des problèmes de compilateur. Par JDK-8 publication officielle ceci est devenu hors de propos. Maintenant, l'opérateur ternaire dans ce code fonctionne comme prévu (pas de référence à Executable
class dans compilé .classe-fichier est présent).
actuellement des choses similaires apparaissent dans JDK-9: un code qui peut être compilé correctement dans JDK-8 est échoué avec JDK-9 javac. Je suppose que la plupart de ces problèmes seront résolus jusqu'à la sortie.
if
else
est un bloc alors que le ternaire (plus connu sous le nom d'opérateur conditionnel en Java) est une expression .
Un déclaration peut faire des choses comme return
à l'appelant sur certains chemins de contrôle. Une expression peut être utilisée dans une cession:
int n = condition ? 3 : 2;
ainsi les deux expressions dans le ternaire après la condition doivent être coercables au même type. Cela peut causer des effets étranges en Java, en particulier avec l'auto-boxe et le casting de référence automatique - c'est ce à quoi se réfère le commentaire dans votre code posté. La coercition des expressions dans votre cas serait à un java.lang.reflect.Executable
type (comme c'est le type le plus spécialisé ) et qui ne existe dans les anciennes versions de Java.
de façon stylistique, vous devez utiliser un bloc if
else
si le code est semblable à une instruction, et un ternaire s'il est semblable à une expression.
bien sûr, vous pouvez faire un bloc if
else
se comporter comme une expression si vous utilisez une fonction lambda.
le type de valeur de retour dans une expression ternaire est affecté par les classes mères, qui ont changé comme décrit dans Java 8.
difficile de voir pourquoi un plâtre n'a pas pu être écrit.