A primeira coisa a ter em mente é que os operadores ternários Java têm um "tipo", e é isso que o compilador determinará e considerará, independentemente dos tipos reais / reais do segundo ou terceiro parâmetro. Dependendo de vários fatores, o tipo de operador ternário é determinado de diferentes maneiras, conforme ilustrado na Java Language Specification 15.26
Na pergunta acima, devemos considerar o último caso:
Caso contrário, o segundo e o terceiro operandos são do tipo S1 e S2, respectivamente. Seja T1 o tipo resultante da aplicação da conversão de boxe em S1 e T2 seja o tipo resultante da aplicação da conversão de boxe em S2 . O tipo da expressão condicional é o resultado da aplicação da conversão de captura (§5.1.10) em lub (T1, T2) (§15.12.2.7).
Esse é, de longe, o caso mais complexo, depois de aplicar a conversão de captura (§5.1.10) e, principalmente, em lub (T1, T2) .
Em inglês simples e após uma extrema simplificação, podemos descrever o processo como o cálculo da "Superclasse Menos Comum" (sim, pense no LCM) do segundo e terceiro parâmetros. Isso nos dará o operador ternário "tipo". Novamente, o que acabei de dizer é uma simplificação extrema (considere as classes que implementam várias interfaces comuns).
Por exemplo, se você tentar o seguinte:
long millis = System.currentTimeMillis();
return(true ? new java.sql.Timestamp(millis) : new java.sql.Time(millis));
Você notará que o tipo resultante da expressão condicional é java.util.Date
uma vez que é a "Superclasse Menos Comum" do par Timestamp
/ Time
.
Como null
pode ser autoboxed para qualquer coisa, a "Superclasse Menos Comum" é a Integer
classe e este será o tipo de retorno da expressão condicional (operador ternário) acima. O valor de retorno será um ponteiro nulo do tipo Integer
e é isso que será retornado pelo operador ternário.
Em tempo de execução, quando a Máquina Virtual Java unboxes a Integer
um NullPointerException
é lançada. Isso acontece porque a JVM tenta chamar a função null.intValue()
, onde null
é o resultado da caixa automática.
Na minha opinião (e como minha opinião não está na Especificação de linguagem Java, muitas pessoas acharão errado de qualquer maneira), o compilador faz um mau trabalho ao avaliar a expressão em sua pergunta. Dado que você escreveu, true ? param1 : param2
o compilador deve determinar imediatamente que o primeiro parâmetro - null
- será retornado e deverá gerar um erro no compilador. Isso é um pouco parecido com quando você escreve while(true){} etc...
e o compilador reclama do código abaixo do loop e o sinaliza Unreachable Statements
.
Seu segundo caso é bem direto e essa resposta já é muito longa ...;)
CORREÇÃO:
Depois de outra análise, acredito que errei ao dizer que um null
valor pode ser colocado em caixa / caixa automática para qualquer coisa. Falando sobre a classe Inteiro, o boxe explícito consiste em invocar o new Integer(...)
construtor ou talvez o Integer.valueOf(int i);
(encontrei esta versão em algum lugar). O primeiro jogaria um NumberFormatException
(e isso não acontece) enquanto o segundo simplesmente não faria sentido, pois um int
não pode ser null
...
int foo = (true ? null : 0)
enew Integer(null)
ambos compilam bem, o segundo é a forma explícita de autoboxing.