1. Will finally{} block always be executed?
Statement block finally{} not be always executed, only by the condition of the try{} statment block is executed, then the finally{} will be executed possibly. I say it is possible to be executed is because of :
- It is possible that the whole JVM instance might shutdown abruptly when in the process of executing the statement in try{} block or catch{} block, e.g., you might call System.exit(0) to shutdown JVM when the application is in progress.
- The thread is interrupted or killed when the executing the statement in try{} block or catch{} block.
- System crashed or power off.(a bit of crap)
Normally, finally{} block is always executed before statement return or continue or break.
catch{} block or finally{} block or both of them have to be followed by try{} block.
public class Finally{
public static int test() {
int i = 1;
try {
System.out.println("try block");
System.exit(0);
return i;
} finally {
System.out.println("finally block");
}
}
public static void main(String[] args) {
System.out.println("return value of test(): " + test());
}
}
The result of execution: try block
2. The order of executing try{}/catch{}/finally{}
2.1. Controll transfer statement
In Java, there are four controll transfer statements, return/throw/break/continue. The return statement or throw statement will transfer the controll to its invoker, but break statement or continue statement just transfers the controll within its method.
2.2. The order of execution
The entire process of executing code with try{}catch{}finall{} blocks as following:
- Firstly, assign an initial value 0 to a variable i at index 0 of Local Variables of Stack Frame, then modify the value of i in try{} block or catch{} block, last again assign the modified new value to variable i.
- Secondly, the JVM will instantly copy the value of i to i_copy, and store the value of i_copy to the index 1 of Local Variables.
- Thirdly, the value for controll transfer statement, specially referring return statement or throw statemetn, in try{} or catch{} block comes from i_copy, while in finally{} block comes from i, they not affect each other.
- Last, if the controll transfer statement is out of try{}/catch{}/finally{}, then the final value comes from the i(last modified by finally{} block).
The entire flow as below screenshot:

There are two keys of the order of executing try{}/catch{}/finally{}: 1)whose controll transfer statement woks in the entire method; 2)the Local Variables will backup the value of local variable modified in try{} or catch{} block.
3. Control transfer statement works in try{}
The control transfer statement works in try{} block means there is a return/throw/continue/break statment in try{} block but finally{} block not contains it. The statements in finally{} block will be executed before control transfer statement to be executed, and the value used to transfer(specially referred to return or throw) from try{} block comes from i_copy.
3.1. Finally{} always be executed before return/throw
The statements in finally{} block always be executed before return or throw in try{} block.
public class Finally {
public static void main(String[] args) {
try {
System.out.println("try block");
return;
} finally {
System.out.println("finally block");
}
}
}
The result of execution:
try block finally block
3.2. The value comes from i_copy
There is a complicated example to illustrate the value used to return in try{} block comes from i_copy.
public class Finally{
public static int getValue() {
int i = 1;
try {
return i;
} finally {
// the result from ++i or i=i+1 is as same as each other
i++;
}
}
public static void main(String[] args) {
System.out.println("return value of getValue(): " + getValue());
}
}
The result of execution : return value of getValue: 1
We can check the bytecode mnemonic decompiled from Finally.class file:
public static int getValue();
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=3, args_size=0
0: iconst_1
1: istore_0
2: iload_0
3: istore_1
4: iinc 0, 1
7: iload_1
8: ireturn
9: astore_2
10: iinc 0, 1
13: aload_2
14: athrow
Exception table:
from to target type
2 4 9 any
9 10 9 any
Let’s check the process of calculation in Local Variables:

4. Control transfer statement works in catch{}
Even through the control transfer statement work in catch{} block, the statements in finlly{} block will be still executed before the transfer statement executes, and the value used to transfer(return or throw) also comes from i_copy. Check a instance.
public class Finally {
public static int test(){
int i = 1;
try {
System.out.println("try block");
i++;
i = 1 / 0;
// the return statement cannot miss, as the compiler
// cannot detect the runtime exception and will think
// the method missed a return value.
return i;
} catch (Exception e) {
System.out.println("exception block i : " + i);
return i;
} finally {
++i;
System.out.println("finally block i : " + i);
}
}
public static void main(String[] args) {
System.out.println("return value of test() : " + test());
System.out.println("##########################");
}
}
The result of execution:
try block java.lang.ArithmeticException: / by zero at Finally.test(Finally.java:7) at Finally.main(Finally.java:19) exception block i : 2 finally block i : 3 return value of test() : 2 ##########################
5. Control transfer statement works in finally{} [KEY]
If there are two control transfer statements exists in try{}(or catch{}) block and finally{} block individually, then the transfer statement from finally{} will disable the transfer statement from try{} or catch{}. This is because of the statements in finally{} block are always executed before try{} or catch{}. Let’s check a example to illutrate the function of disable.
public class Finally {
public static int test() {
try {
System.out.println("try block");
return 0;
} finally {
System.out.println("finally block");
return 1;
}
}
public static void main(String[] args) {
System.out.println("return value of test(): " + test());
}
}
The result of execution:
try block finally block return value of test(): 1
Analyse above example, finally{} block would be executed before the return statemet executes in try{}; so when finish the execution of System.out.println(“try block”), the finally{} is executed; in finally{} block, the right of control of test() method transfers to its invoker, the main() method; so the statement of return 0 in try{} will not be executed.
I wanna give another example to explain the value used to return or throw in finally{} block comes from i that indexed 0 in Local Variables.
public class Finally {
public static int test(){
int i = 1;
try {
System.out.println("try block");
i++;
i = 1 / 0;
return i;
} catch (Exception e) {
++i;
System.out.println("exception block i : " + i);
} finally {
++i;
System.out.println("finally block i : " + i);
return i;
}
}
public static void main(String[] args) {
System.out.println("return value of test() : " + test());
}
}
try block exception block i : 3 finally block i : 4 return value of test() : 4
6. Control transfer statement works out of try{}/catch{}/finally{}
All of the three blocks try{}/catch{}/finally{} have no one control transfer statement, or have but not work, then the value used to final return(or throw) comes from the modified value by finally{} block. For instance:
public class Finally {
public static int test() {
int i = 1;
try {
System.out.println("try block");
i++;
i = 1 / 0;
return i;
} catch (Exception e) {
++i;
System.out.println("exception block i : " + i);
} finally {
++i;
System.out.println("finally block i : " + i);
}
return i;
}
public static void main(String[] args) {
System.out.println("return value of test() : " + test());
}
}
try block exception block i : 3 finally block i : 4 return value of test() : 4
7. Finally{} is always executed
Last, finally{} block is always executed before the control transfer statement executes of try{} block or catch{} block.
public class Fianlly {
public static String test1() {
System.out.println("return statement");
return "after return";
}
public static String test() {
try {
System.out.println("try block");
return test1();
} finally {
System.out.println("finally block");
}
}
public static void main(String[] args) {
System.out.println(test());
}
}
try block return statement finally block after return