112 votes

Opérateur ternaire Java vs if / else dans <JDK8 compatibility

Récemment, je suis en train de lire le code source du Framework Spring. Quelque chose que je ne peut 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 est un membre de la classe org.springframework.core.MethodParameter. Le code est facile à comprendre si les observations sont difficiles.

NOTE: pas de ternaire expression de conserver JDK <8 compatibilité, même lorsque vous utilisez le JDK 8 compilateur (potentiellement en sélectionnant java.lang.reflect.Executable comme le type le plus commun, avec cette nouvelle classe de base ne sont pas disponibles sur les anciennes Jdk)

Quelle est la différence entre l'utilisation de ternaire expression et l'utilisation de if...else... construction dans ce contexte?

102voto

dhke Points 2923

Quand vous pensez à ce sujet le type des opérandes, le problème devient plus évident:

this.method != null ? this.method : this.constructor

a type le plus spécialisé de type commun des deux opérandes, c'est à dire le plus spécialisé de type commun aux deux this.method et this.constructor.

Dans Java 7 java.lang.reflect.Member, cependant, la Java 8 bibliothèque de classe introduit un nouveau type java.lang.reflect.Executable ce qui est plus spécialisé que le générique Member. Donc avec Java 8 la bibliothèque de la classe, le type de résultat de l'expression ternaire est - Executable plutôt que d' Member.

Certains (pré-presse) les versions de Java 8 compilateur semblent avoir produit une référence explicite à l' Executable à l'intérieur du code généré lors de la compilation de l'opérateur ternaire. Cela entraînerait une charge de classe, et ainsi tour à tour une ClassNotFoundException lors de l'exécution lors de l'exécution d'une bibliothèque de classe < JDK 8, car Executable n'existe que pour JDK ≥ 8.

Comme l'a noté Tagir Valeev dans cette réponse, c'est effectivement un bug dans les pré-versions de JDK 8 et a depuis été corrigé, donc, à la fois l' if-else solution de contournement et les commentaires explicatifs sont maintenant obsolètes.

Autre remarque: On pourrait en venir à la conclusion que ce compilateur bug était présent avant Java 8. Cependant, l'octet de code généré pour le ternaire par OpenJDK 7 est le même que le code binaire généré par OpenJDK 8. En fait, le type de l'expression passe complètement sous silence au moment de l'exécution, le code est vraiment seulement un test, d'une succursale, de charge, de retour, sans autres vérifications en cours. Soyez assuré que ce n'est pas un problème (plus) et, en effet, semble avoir été un problème temporaire au cours du développement de Java 8.

30voto

Tagir Valeev Points 14218

Cela a été introduit dans de très vieux s'engager au 3 Mai 2013, presque un an avant le JDK officiel-8. Le compilateur a été sous la lourde développement de ces moments, de sorte que de tels problèmes de compatibilité peuvent survenir. Je suppose que, le Printemps de l'équipe juste testé le JDK-8 construire et a tenté de résoudre les problèmes, même s'ils sont réellement des problèmes du compilateur. Par JDK-8 version officielle c'est devenu hors de propos. Maintenant, l'opérateur ternaire dans ce code fonctionne comme prévu (pas de référence à l' Executable de la classe dans compilé .classe-fichier est présent).

Actuellement, des choses semblables apparaissent dans le JDK-9: un bout de code qui peut être bien compilé dans le JDK-8 est échoué avec le JDK-9 javac. Je suppose que, pour la plupart, ces problèmes seront corrigés jusqu'à la libération.

7voto

Bathsheba Points 23209

La différence principale est qu'un if else d'un bloc est une déclaration attendu que le ternaire (le plus souvent connu comme le conditionnel opérateur en Java) est une expression.

Une déclaration peut faire des choses comme return de l'appelant sur certains chemins de contrôle. Une expression peut être utilisée dans une affectation:

int n = condition ? 3 : 2;

Ainsi, les deux expressions dans le ternaire après que la condition nécessaire pour être coercable du même type. Cela peut provoquer quelques effets bizarres en Java, en particulier avec l'auto-boxing et de référence automatique de moulage - c'est ce que le commentaire posté code fait référence. La contrainte des expressions dans votre cas serait d'un java.lang.reflect.Executable type (comme c'est le plus spécialisé de type) et qui n'existe pas dans les anciennes versions de Java.

Stylistiquement, vous devez utiliser un if else bloc si le code est relevé, et un ternaire si c'est l'expression-comme.

Bien sûr, vous pouvez faire une if else bloc se comporter comme une expression si vous utilisez une fonction lambda.

6voto

EJP Points 113412

Le type de valeur de retour dans une expression ternaire est affecté par les classes parentes, qui ont changé comme décrit dans Java 8.

Difficile de voir pourquoi une distribution n'aurait pas pu être écrite.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X