Por que o compilador Java não entende essa variável é sempre inicializado?

class Foo{ public static void main(String args[]){ final int x=101; int y; if(x>100){ y=-1; } System.out.println(y); } } 

O compilador Java entende que a condição da instrução if é sempre verdadeira e, portanto, y sempre será inicializada. Nenhum erro de compilation, conforme esperado.

 class Bar{ public static void main(String args[]){ final int x; x=101; int y; if(x>100){ y=-1; } System.out.println(y); } } 

Mas quando eu quebro a declaração e a boot de x em duas linhas, o compilador parece não entender que a condição é sempre verdadeira e y sempre será inicializada.

 final int x; x=101; byte b; b=x; System.out.println(b); 

A mesma coisa acontece aqui e o compilador dá uma perda de erro de precisão.

 final int x=101; byte b; b=x; System.out.println(b); 

Novamente, o compilador pode entender que x está dentro do intervalo de b.

Tem a ver com como o compilador determina se uma declaração será executada ou não. Está definido no JLS # 16 :

Cada variável local e cada campo final em branco deve ter um valor definitivamente atribuído quando ocorre qualquer access de seu valor.

No seu caso, o compilador não pode determinar que y foi definitivamente atribuído e lhe dá um erro. Isso ocorre porque seria necessário determinar se a condição é sempre verdadeira e isso só é possível se a condição no if for uma expressão constante .

JLS # 15.28 define expressões constantes :

Uma expressão constante em tempo de compilation é uma expressão denotando um valor de tipo primitivo ou uma String que não é concluída abruptamente e é composta usando apenas o seguinte:

  • […]
  • Nomes simples (§6.5.6.1) que se referem a variables ​​constantes (§4.12.4).

O JLS # 4.12.4 define variables ​​de constantes como:

Uma variável do tipo primitivo ou tipo String, que é final e inicializada com uma expressão constante em tempo de compilation, é chamada de variável constante.

No seu caso, final int x = 101; é uma variável constante mas final int x; x = 101; final int x; x = 101; não é.

Como parte do objective de portabilidade, existe um conjunto muito específico de regras para o que um compilador deve aceitar e o que ele deve rejeitar. Essas regras permitem e exigem apenas uma forma limitada de análise de stream ao determinar se uma variável é definitivamente atribuída ao seu uso.

Veja a Especificação da Linguagem Java, Capítulo 16. Atribuição Definida

A regra crítica é aquela em 16.2.7. if Declarações , caso “se (e) S”. A regra para ser definitivamente atribuído se expande para:

V é atribuído após if (e) S if, e somente se, V é atribuído após S e V serem atribuídos após e quando false.

y é o relevante V. Não é atribuído antes da instrução if. É de fato atribuído após S , y = {y = -1;} mas não há nada que o faça atribuído quando x> 100 é falso.

Assim, y não é atribuído definitivamente após a instrução if.

Uma análise de stream mais completa determinaria que a condição x> 100 é sempre verdadeira, mas o JLS exige que o compilador rejeite o programa com base nessas regras específicas.

A variável final está bem. A regra é, na verdade:

“É um erro em tempo de compilation se uma variável final é atribuída a menos que seja definitivamente não atribuída (§16) imediatamente antes da atribuição.”

A declaração deixa definitivamente não atribuída, e até mesmo a análise de stream limitado pode determinar que x ainda é definitivamente não atribuído na atribuição.

O que você fez para a variável x no segundo código é chamado de variável final em branco . Se uma variável final não é inicializada quando é declarada, então ela é conhecida como uma variável final em branco.

Muitos desenvolvedores Java pensam que o valor de uma variável final é conhecido no tempo de compilation. Isto não é sempre verdade. Diz-se que o valor de uma variável final em branco NÃO é conhecido no momento da compilation. Daí seu segundo código lhe dará um erro de compilation. O compilador pode ver que você inicializou a variável final x , mas a compilation não sabe seu valor. Portanto, o compilador não pode resolver a instrução if. Por isso, pensa que a variável y não é inicializada.

Você pode ler mais sobre as variables ​​finais do Java aqui .