Java conditional operator: type de résultat

je suis un peu perplexe au sujet de l'opérateur conditionnel. Considérons les deux lignes suivantes:

Float f1 = false? 1.0f: null;
Float f2 = false? 1.0f: false? 1.0f: null;

pourquoi f1 devient nul et la seconde déclaration lance une NullPointerException?

Langspec-3.0 para 15.25 sais:

dans les autres cas, les deuxième et troisième opérandes sont des types S1 et S2 respectivement. Que T1 soit le type qui résulte de l'application de la conversion de boxe à S1, et que T2 soit le type cela résulte de l'application de la conversion de boxe à S2. Le type de l'expression conditionnelle est le résultat de l'application de capture de conversion (§5.1.10) à lub (T1, T2) (§15.12.2.7).

Donc, pour false?1.0f:null T1 est le Flotteur et T2 est le type null. Mais quel est le résultat de lub(T1,T2) ? Ce paragraphe 15.12.2.7 est un peu trop ...

BTW, j'utilise 1.6.0_18 sous Windows.

PS: je sais que Float f2 = false? (Float) 1.0f: false? (Float) 1.0f: null; ne Lancez NPE.

36
demandé sur Mechanical snail 2010-04-11 03:53:53

5 réponses

la différence est un typage statique des expressions au moment de la compilation:

résumé

E1: `(false ? 1.0f : null)`
    - arg 2 '1.0f'           : type float,
    - arg 3 'null'           : type null 
    - therefore operator ?:  : type Float (see explanation below)
    - therefore autobox arg2
    - therefore autobox arg3

E2: `(false ? 1.0f : (false ? 1.0f : null))`
    - arg 2 '1.0f'                    : type float
    - arg 3 '(false ? 1.0f : null)'   : type Float (this expr is same as E1)
    - therefore, outer operator ?:    : type float (see explanation below)
    - therefore un-autobox arg3

Explication Détaillée:

voici ma compréhension à partir de la lecture de la spécification et de travailler à l'envers à partir du résultat que vous avez obtenu. Il s'agit du type du troisième opérande de la f2 intérieure conditionnelle est de type nul tandis que le type de le troisième opérande du F2 extérieur conditionnel est considéré comme flottant.

Note: il est important de se rappeler que la détermination du type et l'insertion du code de boxe/déballage se font au moment de la compilation. L'exécution du code boxing/unboxing se fait à l'exécution.

Float f1 = (false ? 1.0f : null);
Float f2 = (false ? 1.0f : (false ? 1.0f : null));

La f1 conditionnelle et la f2 intérieure conditionnel: (faux ? 1.0 f: null)

le conditionnel f1 et le conditionnel interne f2 sont identiques: (faux ? 1.0 f: null) . Les types d'opérandes du conditionnel f1 et du conditionnel interne f2 sont:

type of second operand = float
type of third operand = null type (§4.1)

la plupart des règles de §15.25 sont ignorées et cette évaluation finale est effectivement appliquée:

dans les autres cas, les deuxième et troisième opérandes sont des types S1 et S2 respectivement. Que T1 soit le type qui résulte de l'application de la conversion de boxe à S1, et que T2 soit le type qui résulte de l'application de la conversion de boxe à S2. Le type d'expression conditionnelle est le résultat de l'application de la conversion de capture ( §5.1.10 ) à lub (T1, T2) ( §15.12.2.7 ).

S1 = float
S2 = null type
T1 = Float
T2 = null type
type of the f1 and f2 inner conditional expressions = Float

puisque pour f1, l'affectation est à une variable de référence Float, le résultat de l'expression (null) est attribués correctement.

f2 extérieur conditionnel: (faux ? 1,0 F : [F2 interne conditionnel])

pour la condition extérieure f2, les types sont:

type of second operand = float
type of third operand = Float

Note la différence dans l'opérande types par rapport à la f1/f2 intérieure des conditions qui font référence à la null littérale directement ( §4.1 ). En raison de cette différence de ayant 2 types numériques-convertibles, cette règle de §15.12.2.7 s'applique:

  • autrement, si les deuxième et troisième opérandes ont des types qui sont convertibles ( §5.1.8 ) aux types numériques, puis il y a plusieurs cas: ...

    • sinon, promotion numérique binaire( §5.6.2 ) est appliqué aux types d'opérande, et le le type de l'expression conditionnelle est le type promu des deuxième et troisième opérandes. Notez que la promotion numérique binaire effectue la conversion unboxing ( §5.1.8 ) et la conversion de l'ensemble des valeurs( §5.1.13 ).

en raison de la conversion Unbox effectuée sur le résultat du conditionnel interne f2 (null), une NullPointerException est soulever.

26
répondu Bert F 2011-09-20 22:10:47

ce qui suit lancera un NPE pendant que vous tentez d'attribuer un nul à une primitive

    float f1 = false ? 1.0f: null;

qui je crois est ce qui cause le NPE dans la deuxième déclaration. Parce que le premier ternaire renvoie un float pour true il tente de convertir le false en un float aussi bien.

la première déclaration ne sera pas convertie en null car le résultat requis est un flottant

cela par exemple ce ne serait pas jeter un NPE comme son plus doit se convertir en primitif

    Float f = false? new Float(1.0f): true ? null : 1.0f;
2
répondu objects 2010-04-11 00:28:27

je pense que réécrire le code rend l'explication plus claire:

    float f = 1.0f;

    Float null_Float  = false?        f  : null;       // float + null  -> OK
    Float null_Float2 = false? (Float)f  : null_Float; // Float + Float -> OK
    Float npe         = false?        f  : null_Float; // float + Float -> NPE

ainsi le NPE est quand nous essayons de faire quelque chose comme:

Float npe = false? 1.0f : (Float)null;
2
répondu JRL 2010-04-11 01:26:31

être ou ne pas être, telle est la question. :)

Edit: en fait, en regardant de plus près, il semble que ce cas est en fait un mélange entre le Hamlet (opérateur ternaire et les types entiers enveloppés) et le Elvis (auto-unboxing null) puzzlers. Dans tous les cas, je ne peux que recommander de regarder la vidéo, elle est très éducative et agréable.

2
répondu kloffy 2010-04-11 01:48:38

on dirait que la JVM tente de déboxifier le second nul à float au lieu de Float , donc NullPointerException. Frapper moi-même une fois. Mon avis est que le deuxième si le fait parce que le vrai partie du premier si évalue comme un flotteur, pas un flotteur.

après y avoir réfléchi, je pense que C'est une façon de Java de vous dire que vous êtes faire quelque chose d'étrange. Il suffit de ne pas nid ternaire fi et tout ira bien :-)

1
répondu Slava Imeshev 2010-04-11 02:22:16