Questão 1:
Por que o código a seguir é compilado sem ter uma declaração de retorno?
public int a()
{
while(true);
}
Isso é coberto pelo JLS§8.4.7 :
Se um método for declarado com um tipo de retorno (§8.4.5), ocorrerá um erro em tempo de compilação se o corpo do método puder ser concluído normalmente (§14.1).
Em outras palavras, um método com um tipo de retorno deve retornar apenas usando uma instrução de retorno que forneça um retorno de valor; o método não tem permissão para "deixar o final do corpo". Veja §14.17 para as regras precisas sobre instruções de retorno em um corpo de método.
É possível que um método tenha um tipo de retorno e ainda não contenha instruções de retorno. Aqui está um exemplo:
class DizzyDean {
int pitch() { throw new RuntimeException("90 mph?!"); }
}
Como o compilador sabe que o loop nunca terminará ( true
sempre é verdade, é claro), sabe que a função não pode "retornar normalmente" (deixar o final do corpo) e, portanto, não há problema return
.
Questão 2:
Por outro lado, por que o código a seguir compila,
public int a()
{
while(0 == 0);
}
mesmo que o seguinte não.
public int a(int b)
{
while(b == b);
}
No 0 == 0
caso, o compilador sabe que o loop nunca terminará (isso 0 == 0
sempre será verdadeiro). Mas não sabe disso b == b
.
Por que não?
O compilador entende expressões constantes (§15.28) . Citação §15.2 - Formas de expressão (porque estranhamente esta frase não está em §15.28) :
Algumas expressões têm um valor que pode ser determinado em tempo de compilação. Essas são expressões constantes (§15.28).
No seu b == b
exemplo, como há uma variável envolvida, ela não é uma expressão constante e não é especificada para ser determinada no momento da compilação. Podemos ver que sempre será verdade neste caso (embora, se b
fosse um double
, como o QBrute apontou , poderíamos ser facilmente enganados Double.NaN
, o que não==
é o próprio ), mas o JLS especifica apenas que expressões constantes são determinadas em tempo de compilação , ele não permite que o compilador tente avaliar expressões não constantes. O bayou.io levantou um bom argumento: por que não: Se você começa a tentar determinar expressões que envolvem variáveis no momento da compilação, por onde você pára? b == b
é óbvio (er, para nãoNaN
valores), mas e quanto a + b == b + a
? Ou (a + b) * 2 == a * 2 + b * 2
? Desenhar a linha em constantes faz sentido.
Portanto, como não "determina" a expressão, o compilador não sabe que o loop nunca será encerrado; portanto, ele acha que o método pode retornar normalmente - o que não é permitido, porque é necessário usá-lo return
. Por isso, reclama da falta de um return
.