Enquanto me preparava para o OCPJP 21, me deparei com o tópico Escopo de fluxo.
preciso de alguma orientação para entender o conceito. abaixo está o trecho de código
public class Question28
{
static void getFish(Object fish) {
if(!(fish instanceof String guppy))
System.out.println("Eat!");
else if(!(fish instanceof String guppy)) {
throw new RuntimeException();
}
System.out.println(guppy);
System.out.println("Swim!");
}
public static void main(String args[]) {
getFish("ashish");
}
}
O snippet acima resulta em "Não é possível encontrar o símbolo" para a variável guppy. Mas se eu remover a palavra-chave else, como abaixo. A variável guppy permanece no escopo. Nenhum erro do compilador.
static void getFish(Object fish) {
if(!(fish instanceof String guppy))
System.out.println("Eat!");
if(!(fish instanceof String guppy)) {
throw new RuntimeException();
}
System.out.println(guppy);
minha segunda observação é a seguinte ref snippet
class Sample2 {
static void printNumberTwice(Number number) {
if(!(number instanceof Integer data))
return ;
//System.out.println("Eat!");
System.out.println(data.intValue());
}
public static void main(String args[]) {
printNumberTwice(5);
}
}
O snippet acima compila com sucesso, mas se eu comentar return e adicionar a instrução SOP, o resultado será não é possível encontrar o símbolo para os dados.
por favor me oriente para entender o conceito.
Você só pode usar a variável se o compilador puder provar que o código só será executado se o padrão corresponder.
Agora, vamos analisar seu exemplo:
Digamos
fish
que não é umString
. Neste caso, ele entraria naif
declaração imprimindoEat!
. Como ele entrou noif
, ele não entra noelse if
então ele continuaria tentando imprimirguppy
- Mas espere, ele não é,String
entãoguppy
pode não existir (ele definitivamente não está atribuído ).Se você pular a
else
palavra-chave, você sempre estará lançando a exceção iffish
isn't aString
. Lá, você só permite a execução paraString
s enduring queguppy
é válido.Agora, vamos verificar também seu segundo exemplo:
Aqui, você pode usar
data
porque o compilador provavelmente sabe quenumber
é umInteger
. Se não for, o fluxo de execução seria cancelado/parado pelareturn
declaração (o que também pode ser feito usando exceções,break;
oucontinue;
).Se você remover o
return
e substituí-lo por uma instrução que não afete o fluxo de controle, a passagem de uma instrução que não sejaString
s poderá fazer com que oSystem.out.println
seja executado.Dito isso, observe que o compilador Java não é um poderoso provador de teoremas e não tenta ser. Ele faz algum trabalho para detectar se as variáveis são atribuídas, mas não é completo (o que seria impossível graças a Gödel), ou seja, há casos em que é impossível que uma declaração seja executada, mas o compilador não sabe. O importante em que o compilador se concentra é a solidez, ou seja, garantir que ele não permita código inválido (e ser previsível e seguir a especificação).