Tengo una clase de Java simple como se muestra a continuación:
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());
}
}
Y el resultado de este código es este:
Entry in finally Block
dev
¿Por qué sno se anula en el finallybloque y controla la salida impresa?
java
try-finally
Dev
fuente
fuente

santes de cambiar su valor.finallybloque , al contrario que en C # (que no se puede)Respuestas:
El
trybloque se completa con la ejecución de lareturndeclaración y el valor desen el momento enreturnque se ejecuta la declaración es el valor devuelto por el método. El hecho de que lafinallycláusula luego cambie el valor des(después de que lareturndeclaración se complete) no (en ese punto) cambia el valor de retorno.Tenga en cuenta que lo anterior trata con cambios en el valor de
ssí mismo en elfinallybloque, no en el objeto al que hacesreferencia. Sisfue una referencia a un objeto mutable (queStringno lo es) y el contenido del objeto se modificó en elfinallybloque, esos cambios se verían en el valor devuelto.Las reglas detalladas sobre cómo funciona todo esto se pueden encontrar en la Sección 14.20.2 de la Especificación del lenguaje Java . Tenga en cuenta que la ejecución de una
returndeclaración cuenta como una terminación abrupta deltrybloque (se aplica la sección que comienza " Si la ejecución del bloque try finaliza abruptamente por cualquier otro motivo R ... "). Ver Sección 14.17 del JLS para ver por qué unareturndeclaración es una terminación abrupta de un bloque.A modo de más detalles: si tanto el
trybloque como elfinallybloque de unatry-finallydeclaración terminan abruptamente debido areturndeclaraciones, entonces se aplican las siguientes reglas del §14.20.2:El resultado es que la
returndeclaración en elfinallybloque determina el valor de retorno de toda latry-finallydeclaración, y el valor devuelto deltrybloque se descarta. Algo similar ocurre en unatry-catch-finallydeclaración si eltrybloque arroja una excepción, es atrapado por uncatchbloque y tanto elcatchbloque como elfinallybloque tienenreturndeclaraciones.fuente
finallybloque no cambia qué objeto se devuelve (elStringBuilder) pero puede cambiar las partes internas del objeto. Elfinallybloque se ejecuta antes de que el método realmente regrese (aunque lareturndeclaración haya finalizado), por lo que esos cambios ocurren antes de que el código de llamada vea el valor devuelto.StringBuilder,List,Set, hasta la saciedad): si cambia el contenido en elfinallybloque, a continuación, se observan los cambios en el código de llamada cuando el método finalmente salidas.Porque el valor de retorno se coloca en la pila antes de la llamada a finalmente.
fuente
=no lo mutaría.finallybloqueo de OP no afectó el valor de retorno. Creo que a lo que templatetypedef podría haber estado llegando (aunque esto no está claro) es que debido a que el valor devuelto es una referencia a un objeto inmutable, incluso cambiar el código en elfinallybloque (aparte de usar otrareturndeclaración) no podría afectar el valor devuelto por el métodoSi miramos dentro de bytecode, notaremos que JDK ha realizado una optimización significativa, y el método foo () se ve así:
Y bytecode:
Java preservó la cadena "dev" de ser cambiada antes de regresar. De hecho, aquí no hay finalmente un bloqueo en absoluto.
fuente
Hay 2 cosas notables aquí:
fuente
finallycláusula, eso se vería en el código de llamada. Sin embargo, si asignó un nuevo buffer de cadenas as, entonces el comportamiento sería el mismo que ahora.Cambio un poco tu código para probar el punto de Ted.
Como puede ver en la salida, de
shecho, cambia pero después del regreso.Salida:
fuente
Técnicamente hablando, el
returnbloque en el try no se ignorará sifinallyse define un bloque, solo si ese bloque finalmente también incluye areturn.Es una decisión de diseño dudosa que probablemente fue un error en retrospectiva (al igual que las referencias son anulables / mutables de forma predeterminada y, según algunos, excepciones marcadas). En muchos sentidos, este comportamiento es exactamente consistente con la comprensión coloquial de lo que
finallysignifica: "no importa lo que ocurra de antemano en eltrybloque, siempre ejecute este código". Por lo tanto, si devuelve verdadero de unfinallybloque, el efecto general siempre debe serreturn s, ¿no?En general, esto rara vez es una buena expresión idiomática, y debe usar
finallybloques generosamente para limpiar / cerrar recursos, pero rara vez devuelve un valor de ellos.fuente
Pruebe esto: si desea imprimir el valor de anulación de s.
fuente