Eu tenho uma classe Java simples, como mostrado abaixo:
public class Test {
private String s;
public String foo() {
try {
s = "dev";
return s;
}
finally {
s = "override variable s";
System.out.println("Entry in finally Block");
}
}
public static void main(String[] xyz) {
Test obj = new Test();
System.out.println(obj.foo());
}
}
E a saída desse código é esta:
Entry in finally Block
dev
Por que s
não é substituído no finally
bloco, ainda controla a saída impressa?
java
try-finally
Dev
fonte
fonte
s
antes de alterar seu valor.finally
bloco , ao contrário de C # (que você não pode)Respostas:
O
try
bloco é concluído com a execução dareturn
instrução e o valor des
no momento em que areturn
instrução é executada é o valor retornado pelo método. O fato de afinally
cláusula alterar posteriormente o valor des
(após a conclusão dareturn
instrução) não muda (nesse ponto) o valor de retorno.Observe que o item acima lida com alterações no valor de
s
si mesmo nofinally
bloco, não no objeto que fazs
referência. Ses
fosse uma referência a um objeto mutável (o queString
não é) e o conteúdo do objeto fosse alterado nofinally
bloco, essas alterações seriam vistas no valor retornado.As regras detalhadas de como tudo isso funciona podem ser encontradas na Seção 14.20.2 da Especificação da linguagem Java . Observe que a execução de uma
return
instrução conta como um término abrupto dotry
bloco (a seção que inicia " Se a execução do bloco try for concluída abruptamente por qualquer outro motivo, R .... " se aplica). Consulte a Seção 14.17 do JLS para saber por que umareturn
instrução é um encerramento abrupto de um bloco.Por meio de mais detalhes: se o
try
bloco e ofinally
bloco de umatry-finally
instrução terminam abruptamente devido areturn
instruções, as seguintes regras do §14.20.2 se aplicam:O resultado é que a
return
instrução nofinally
bloco determina o valor de retorno de toda atry-finally
instrução e o valor retornado dotry
bloco é descartado. O mesmo ocorre em umatry-catch-finally
instrução se otry
bloco lança uma exceção, é capturado por umcatch
bloco e ocatch
bloco e ofinally
bloco têmreturn
instruções.fonte
finally
bloco não altera o objeto retornado (theStringBuilder
), mas pode alterar as partes internas do objeto. Ofinally
bloco é executado antes que o método realmente retorne (mesmo que areturn
instrução tenha sido concluída); portanto, essas alterações ocorrem antes que o código de chamada veja o valor retornado.StringBuilder
,List
,Set
, ad nauseum): se você alterar o conteúdo dofinally
bloco, em seguida, essas mudanças são vistos no código de chamada quando o método finalmente sai.Porque o valor de retorno é colocado na pilha antes da chamada finalmente.
fonte
=
não a modificaria.finally
bloqueio do OP não afetou o valor de retorno. Eu acho que o que templatetypedef poderia estar chegando (embora isso não esteja claro) é que, porque o valor retornado é uma referência a um objeto imutável, mesmo alterar o código nofinally
bloco (exceto usar outrareturn
instrução) não poderia afetar o valor retornado do métodoSe olharmos dentro do bytecode, perceberemos que o JDK fez uma otimização significativa e o método foo () se parece com:
E bytecode:
java preservou a string "dev" antes de retornar. De fato, aqui não há finalmente um bloqueio.
fonte
Há duas coisas dignas de nota aqui:
fonte
finally
cláusula, isso seria visto no código de chamada. No entanto, se você atribuiu um novo buffer de seqüência de caracteres as
, então o comportamento seria o mesmo de agora.Mudo um pouco o seu código para provar o ponto de vista de Ted.
Como você pode ver na saída
s
é realmente alterado, mas após o retorno.Resultado:
fonte
Tecnicamente falando, o
return
bloco try não será ignorado se umfinally
bloco for definido, apenas se esse bloco finalmente também incluir areturn
.É uma decisão de projeto duvidosa que provavelmente foi um erro em retrospecto (bem como referências sendo anuláveis / mutáveis por padrão e, de acordo com algumas, exceções verificadas). De muitas maneiras, esse comportamento é exatamente consistente com o entendimento coloquial do que
finally
significa - "não importa o que aconteça de antemão notry
bloco, sempre execute esse código". Portanto, se você retornar verdadeiro de umfinally
bloco, o efeito geral sempre deve serreturn s
, não?Em geral, esse raramente é um bom idioma, e você deve usar
finally
blocos liberalmente para limpar / fechar recursos, mas raramente, se é que alguma vez, retorna um valor a partir deles.fonte
Tente isto: Se você deseja imprimir o valor de substituição de s.
fonte