Last time I was reviewing a code and found out something interesting regarding the Java finally-clause. Suppose we have the code below which adds strings to a StringBuilder and returns this object.
public StringBuilder finallyReturnString() {
StringBuilder s = new StringBuilder();
s.append("init");
try {
s.append("-try");
return s;
} finally {
s.append("-finally");
}
}
It will return a StringBuilder containing “init-try-finally”. However, let’s dissemble the code above.
0: new #23; //class java/lang/StringBuilder
3: dup
4: invokespecial //StringBuilder()
7: astore_1
8: aload_1
9: ldc #80; //String init
11: invokevirtual //StringBuilder.append()
14: pop
15: aload_1
16: ldc #82; //String -try
18: invokevirtual #36; //StringBuilder.append()
21: pop
22: aload_1
23: astore_3
24: aload_1
25: ldc #84; //String -finally
27: invokevirtual //StringBuilder.append()
30: pop
31: aload_3
32: areturn
33: astore_2
34: aload_1
35: ldc #84; //String -finally
37: invokevirtual //StringBuilder.append()
40: pop
41: aload_2
42: athrow
Here the try-clause is represented by the lines 15-23 and 31-32 and the finally-clause between the lines 24-30. The "finally" string is appended to the variable 1 or 3 and then “init-try-finally” contained in variable 3 is returned. You may have noticed that the finally-clause is repeated at lines 35-40.
Now let's take a similar example. Here we will not append string but set a new String each time. This will return "try" and not "finally".
public StringBuilder finallyReturnString() {
StringBuilder s = new StringBuilder("init");
try {
s = new StringBuilder("try");
return s;
} finally {
s = new StringBuilder("finally");
}
}
The disassembled code looks like:
0: new #23; //class java/lang/StringBuilder
3: dup
4: ldc #79; //String init
6: invokespecial //StringBuilder(String)
9: astore_1
10: new #23; //class java/lang/StringBuilder
13: dup
14: ldc #65; //String try
16: invokespecial //StringBuilder(String)
19: astore_1
20: aload_1
21: astore_3
22: new #23; //class java/lang/StringBuilder
25: dup
26: ldc #73; //String finally
28: invokespecial //StringBuilder(String)
31: astore_1
32: aload_3
33: areturn
34: astore_2
35: new #23; //class java/lang/StringBuilder
38: dup
39: ldc #73; //String finally
41: invokespecial //StringBuilder(String)
44: astore_1
45: aload_2
46: athrow
Here the the try-clause is represented by the lines 10-21 and 32-33, and the finally-clause by the lines 22-31. "init" and "try" strings are stored in variables 1 and 3. "finally" string is stored in variable 1 but variable 3 which contains "try" is returned.
This time, we will make things more clear in case you did not catch the twist; we will use String (immutable class) as a return type. The finallyReturnString() will also return "try".
public String finallyReturnString() {
String s = "init";
try {
s = "try";
return s;
} finally {
s = "finally";
}
}
The disassembled code looks like:
0: ldc #75; //String init
2: astore_1
3: ldc #61; //String try
5: astore_1
6: aload_1
7: astore_3
8: ldc #69; //String finally
10: astore_1
11: aload_3
12: areturn
13: astore_2
14: ldc #69; //String finally
16: astore_1
17: aload_2
18: athrow
The try-clause is represented by lines 3-7 and 11-12, and the finally-clause by the lines 8-10. Same as previous example, "init" and "try" string are stored in variables 1 and 3. "finally" string is stored in variable 1 but variable 3 which contains "try" is returned.
Next time when you have a return statement in your try-clause combined with finally-clause which affects variables, watch-out! May be you need to refactor your code!
No comments:
Post a Comment