Houve alguma razão pela qual os designers de Java sentiram que variáveis locais não deveriam receber um valor padrão? Sério, se variáveis de instância podem receber um valor padrão, então por que não podemos fazer o mesmo para variáveis locais?
E também leva a problemas, conforme explicado neste comentário em uma postagem do blog :
Bem, esta regra é mais frustrante ao tentar fechar um recurso em um bloco final. Se eu instanciar o recurso em uma tentativa, mas tento fechá-lo no finalmente, recebo este erro. Se eu mover a instanciação fora do try, recebo outro erro informando que deve estar dentro de um try.
Muito frustrante.
java
variables
initialization
Shivasubramanian A
fonte
fonte
Respostas:
Variáveis locais são declaradas principalmente para fazer alguns cálculos. Portanto, é decisão do programador definir o valor da variável e não deve assumir um valor padrão. Se o programador, por engano, não inicializou uma variável local e assumiu o valor padrão, então a saída pode ser algum valor inesperado. Portanto, no caso de variáveis locais, o compilador pedirá ao programador para inicializar com algum valor antes de acessar a variável para evitar o uso de valores indefinidos.
fonte
O "problema" que você vincula parece descrever esta situação:
A reclamação do comentarista é que o compilador recua na linha da
finally
seção, alegando queso
pode não ter sido inicializado. O comentário então menciona outra maneira de escrever o código, provavelmente algo assim:O comentarista não está satisfeito com a solução porque o compilador diz que o código "deve estar dentro de uma tentativa". Acho que isso significa que parte do código pode gerar uma exceção que não é mais tratada. Não tenho certeza. Nenhuma das versões do meu código lida com exceções, portanto, qualquer coisa relacionada a exceções na primeira versão deve funcionar da mesma forma na segunda.
De qualquer forma, essa segunda versão de código é a maneira correta de escrevê-lo. Na primeira versão, a mensagem de erro do compilador estava correta. A
so
variável pode não ter sido inicializada. Em particular, se oSomeObject
construtor falhar,so
não será inicializado e, portanto, será um erro tentar chamarso.CleanUp
. Sempre entre natry
seção depois de ter adquirido o recurso que afinally
seção finaliza.O bloco
try
-finally
após aso
inicialização existe apenas para proteger aSomeObject
instância, para garantir que ela seja limpa, não importa o que mais aconteça. Se houver outras coisas que precisam ser executadas, mas não estão relacionadas ao fato de aSomeObject
instância ter sido alocada por propriedade, elas devem ir para outro blocotry
-finally
, provavelmente um que envolva o que eu mostrei.Exigir que as variáveis sejam atribuídas manualmente antes do uso não leva a problemas reais. Isso só leva a pequenos aborrecimentos, mas seu código será melhor para isso. Você terá variáveis com escopo mais limitado e
try
-finally
blocos que não tentam proteger muito.Se as variáveis locais tivessem valores padrão,
so
no primeiro exemplo teriam sidonull
. Isso realmente não teria resolvido nada. Em vez de obter um erro de tempo de compilação nofinally
bloco, você teria um erro àNullPointerException
espreita que poderia ocultar qualquer outra exceção que pudesse ocorrer na seção "Faça algum trabalho aqui" do código. (Ou as exceções nasfinally
seções acorrentam automaticamente à exceção anterior? Não me lembro. Mesmo assim, você teria uma exceção extra no caminho da real.)fonte
Além disso, no exemplo abaixo, uma exceção pode ter sido lançada dentro da construção SomeObject, caso em que a variável 'so' seria nula e a chamada para CleanUp lançará um NullPointerException
O que costumo fazer é o seguinte:
fonte
Observe que as variáveis de instância / membro finais não são inicializadas por padrão. Porque esses são finais e não podem ser alterados no programa posteriormente. Essa é a razão pela qual o Java não fornece nenhum valor padrão para eles e força o programador a inicializá-lo.
Por outro lado, as variáveis de membro não finais podem ser alteradas posteriormente. Conseqüentemente, o compilador não permite que eles permaneçam não inicializados, precisamente porque eles podem ser alterados posteriormente. Em relação às variáveis locais, o escopo das variáveis locais é muito mais restrito. O compilador sabe quando está sendo usado. Portanto, forçar o programador a inicializar a variável faz sentido.
fonte
A resposta real à sua pergunta é porque as variáveis do método são instanciadas simplesmente adicionando um número ao ponteiro da pilha. Zerá-los seria uma etapa extra. Para variáveis de classe, elas são colocadas na memória inicializada no heap.
Por que não dar um passo extra? Dê um passo para trás - Ninguém mencionou que o "aviso" neste caso é uma coisa muito boa.
Você nunca deve inicializar sua variável para zero ou nulo na primeira passagem (quando você está codificando-a pela primeira vez). Atribua-o ao valor real ou não atribua-o de forma alguma, porque se não o fizer, então o java pode dizer quando você realmente estragar tudo. Veja a resposta de Electric Monk como um ótimo exemplo. No primeiro caso, é realmente muito útil dizer que se o try () falhar porque o construtor de SomeObject lançou uma exceção, você acabaria com um NPE no finally. Se o construtor não pode lançar uma exceção, não deve ser na tentativa.
Este aviso é um verificador de programador ruim de vários caminhos incrível que me salvou de fazer coisas estúpidas, uma vez que verifica todos os caminhos e garante que, se você usar a variável em algum caminho, será necessário inicializá-la em todos os caminhos que levam a ele . Agora, nunca inicializo variáveis explicitamente até determinar que é a coisa certa a fazer.
Além disso, não é melhor dizer explicitamente "int size = 0" em vez de "int size" e fazer o próximo programador descobrir que você pretende que seja zero?
Por outro lado, não consigo encontrar um único motivo válido para que o compilador inicialize todas as variáveis não inicializadas com 0.
fonte
Acho que o objetivo principal era manter a semelhança com C / C ++. No entanto, o compilador detecta e avisa sobre o uso de variáveis não inicializadas, o que reduzirá o problema a um ponto mínimo. Do ponto de vista do desempenho, é um pouco mais rápido permitir que você declare variáveis não inicializadas, pois o compilador não terá que escrever uma instrução de atribuição, mesmo se você substituir o valor da variável na próxima instrução.
fonte
(Pode parecer estranho postar uma nova resposta muito tempo depois da pergunta, mas apareceu uma duplicata .)
Para mim, a razão se resume a isto: o propósito das variáveis locais é diferente do propósito das variáveis de instância. As variáveis locais devem ser usadas como parte de um cálculo; as variáveis de instância existem para conter o estado. Se você usar uma variável local sem atribuir um valor a ela, isso quase certamente é um erro lógico.
Dito isso, eu poderia ficar totalmente atrás de exigir que as variáveis de instância sempre fossem inicializadas explicitamente; o erro ocorreria em qualquer construtor onde o resultado permite uma variável de instância não inicializada (por exemplo, não inicializada na declaração e não no construtor). Mas essa não é a decisão Gosling, et. al., tirou no início dos anos 90, então aqui estamos. (E não estou dizendo que eles fizeram a chamada errada.)
Eu não poderia ficar atrás de variáveis locais padrão, no entanto. Sim, não devemos confiar em compiladores para verificar novamente nossa lógica, e ninguém não, mas ainda é útil quando o compilador detecta um. :-)
fonte
É mais eficiente não inicializar variáveis e, no caso de variáveis locais, é seguro fazê-lo, porque a inicialização pode ser rastreada pelo compilador.
Nos casos em que você precisa que uma variável seja inicializada, você sempre pode fazer isso sozinho, portanto, não é um problema.
fonte
A ideia por trás das variáveis locais é que elas existem apenas dentro do escopo limitado para o qual são necessárias. Como tal, deve haver pouca razão para incerteza quanto ao valor, ou pelo menos, de onde esse valor está vindo. Eu poderia imaginar muitos erros decorrentes de ter um valor padrão para variáveis locais.
Por exemplo, considere o seguinte código simples ... ( NB, vamos supor, para fins de demonstração, que variáveis locais recebem um valor padrão, conforme especificado, se não inicializado explicitamente )
Quando tudo estiver dito e feito, assumindo que o compilador atribuiu um valor padrão de '\ 0' para letterGrade , este código como escrito funcionaria corretamente. No entanto, e se esquecermos a instrução else?
Uma execução de teste do nosso código pode resultar no seguinte
Esse resultado, embora fosse esperado, certamente não era a intenção do codificador. De fato, provavelmente na grande maioria dos casos (ou pelo menos em um número significativo), o valor padrão não seria o valor desejado , portanto, na grande maioria dos casos, o valor padrão resultaria em erro. Faz mais sentido forçar o codificador a atribuir um valor inicial a uma variável local antes de usá-la, uma vez que a dificuldade de depuração causada pelo esquecimento do
= 1
infor(int i = 1; i < 10; i++)
supera em muito a conveniência de não ter que incluir o= 0
infor(int i; i < 10; i++)
.É verdade que os blocos try-catch-finally podem ficar um pouco confusos (mas não é realmente um catch-22 como a citação parece sugerir), quando, por exemplo, um objeto lança uma exceção verificada em seu construtor, ainda para um razão ou outra, algo deve ser feito a este objeto no final do bloco em finalmente. Um exemplo perfeito disso é quando se trata de recursos, que devem ser fechados.
Uma maneira de lidar com isso no passado pode ser assim ...
No entanto, a partir do Java 7, este bloco finalmente não é mais necessário usando try-with-resources, dessa forma.
Dito isso, (como o nome sugere) isso só funciona com recursos.
E embora o exemplo anterior seja um pouco nojento, talvez isso fale mais sobre a maneira como try-catch-finally ou essas classes são implementadas do que sobre variáveis locais e como elas são implementadas.
É verdade que os campos são inicializados com um valor padrão, mas isso é um pouco diferente. Quando você diz, por exemplo,
int[] arr = new int[10];
assim que inicializa este array, o objeto existe na memória em um determinado local. Vamos supor por um momento que não haja valores padrão, mas, em vez disso, o valor inicial é qualquer série de 1s e 0s que esteja naquele local de memória no momento. Isso pode levar a um comportamento não determinístico em vários casos.Suponha que temos ...
Seria perfeitamente possível que
Same.
fosse exibido em uma execução eNot same.
pudesse ser exibido em outra. O problema pode se tornar ainda mais grave quando você começar a falar sobre variáveis de referência.De acordo com a definição, cada elemento de s deve apontar para uma String (ou é nulo). No entanto, se o valor inicial for qualquer série de 0s e 1s que ocorra neste local da memória, não apenas não há garantia de que você obterá os mesmos resultados todas as vezes, mas também não há garantia de que o objeto s [0] aponta to (assumindo que aponta para algo significativo) até mesmo é um String (talvez seja um Coelho,: p )! Essa falta de preocupação com o tipo iria contra quase tudo que faz o Java Java. Portanto, embora ter valores padrão para variáveis locais possa ser visto como opcional, na melhor das hipóteses, ter valores padrão para variáveis de instância é mais próximo de uma necessidade .
fonte
se eu não estou errado, outro motivo poderia ser
Dar o valor padrão das variáveis de membro faz parte do carregamento da classe
O carregamento da classe é uma coisa de tempo de execução em java significa que quando você cria um objeto, a classe é carregada com o carregamento da classe, apenas as variáveis de membro são inicializadas com o valor padrão JVM não leva tempo para fornecer o valor padrão para suas variáveis locais porque alguns métodos nunca serão chamado porque a chamada de método pode ser condicional, então por que perder tempo para dar a eles o valor padrão e reduzir o desempenho se esses padrões nunca serão usados.
fonte
O Eclipse ainda fornece avisos sobre variáveis não inicializadas, então torna-se bastante óbvio de qualquer maneira. Pessoalmente, acho que é uma coisa boa que este seja o comportamento padrão, caso contrário, seu aplicativo pode usar valores inesperados e, em vez de o compilador lançar um erro, ele não fará nada (mas talvez dê um aviso) e então você estará arranhando sua cabeça por que certas coisas não se comportam da maneira que deveriam.
fonte
As variáveis locais são armazenadas em uma pilha, mas as variáveis de instância são armazenadas no heap, portanto, há algumas chances de que um valor anterior na pilha seja lido em vez de um valor padrão, como acontece no heap. Por isso o jvm não permite usar uma variável local sem inicializá-la.
fonte
A variável de instância terá valores padrão, mas as variáveis locais não podem ter valores padrão. Como as variáveis locais estão basicamente em métodos / comportamento, seu objetivo principal é fazer algumas operações ou cálculos. Portanto, não é uma boa ideia definir valores padrão para variáveis locais. Caso contrário, é muito difícil e demorado verificar os motivos de respostas inesperadas.
fonte
A resposta é que as variáveis de instância podem ser inicializadas no construtor de classe ou qualquer método de classe, mas no caso de variáveis locais, uma vez que você definiu o que quer que seja no método que permanece para sempre na classe.
fonte
Eu poderia pensar em seguir 2 motivos
fonte