Comportamento ternário estranho do Java ao atribuir valor. O que o Java está fazendo nos bastidores para que isso aconteça?


10

Alguns dias atrás, encontrei um cenário fascinante em que não encontrava nenhuma documentação sobre como ou por que o Java permite que o seguinte aconteça. (Este trecho é apenas uma forma simplificada do bug.)

    @Test
    public void test() {
      boolean bool = false;
      Integer intVal = Integer.valueOf(5);
      Long longVal = null;
      Long result = bool ? intVal : longVal;

      System.out.println(" > " + result);
   }

no trecho acima:

se o bool = true, então você obtém o valor '5';

mas se bool = false, você recebe uma exceção de ponteiro nulo ao tentar avaliar a operação ternária. NÃO a declaração de impressão.


Para consertar isso, mudei 'resultado' para

Long result = bool ? Long.valueOf(intVal) : longVal;

Fazer isso dará o comportamento esperado que eu precisava:

se o bool = true, então você obtém o valor '5';

mas se bool = false, você obtém 'null'


agora a parte divertida é que, se você dividir isso em uma instrução if / else normal, o java NÃO permitirá que você compile

longVal = intVal; 

mas isso não ocorre através do operador ternário. Então, o que o Java está fazendo para torná-lo nulo no snippet original?

(java 11)

Respostas:


10

Quando você faz isso:

Long result = bool ? intVal : longVal

Essa expressão está retornando ae long, quando boolfalse, tenta unboxe nullpara um valor Long para ajustar a resultvariável e lança um NPE.

Quando você faz isso:

Long result = bool ? Long.valueOf(intVal) : longVal

Esta expressão já está retornando, Longentão não há necessidade de remover a caixa de seleção e o nullvalor é atribuído com êxito à resultvariável.

Referência:

Conforme discutido na seção de comentários, para entender melhor por que isso acontece, verifique as seguintes seções do JLS:


Estou surpreso com a tabela de referência diferente 15.25 A a E, onde é "claro" que Inteiro / Longo resulta em um bnp (Inteiro, Longo).
— matt

Boa resposta. Geralmente, quando não tenho absolutamente nenhuma idéia do que está acontecendo lá dentro, recomendo dar uma olhada no código de código compilado, que revela quase exatamente o que foi descrito. Pelo menos ao extrair um snippet de código mínimo, é mais ou menos uma questão de treinamento como ler e entender.
— Jan Held

Como o JLS, a Seção 5.6.2 diz: "Se algum operando é de um tipo de referência, está sujeito à conversão de unboxing"; então "A conversão primitiva de alargamento (§5.1.2) é aplicada [..]"
— Diego Magdaleno
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.