Return in Try Block vs Return After the Block
I Have a Try Statement in a Small Static Method, Is There a Best Practice as to Where I Should Return from? Try { mightThrow(); Return True; } Catch (Exception...
I have a try statement in a small static method, is there a best practice as to where I should return from?
try {
mightThrow();
return true;
} catch (Exception e) {
return false;
}
or after,
try {
mightThrow();
} catch (Exception e) {
return false;
}
return true;
Functionally, these should preform identically, is there actually a bytecode difference? Performance wise, are they the exact same?
Or is one just preferred over the other? Which and why?
3 Answers
I haven't heard of an actual best practice in this matter, but you often see that when methods use premature returns, the returns true case is at the bottom, e.g.
public bool canReadFile(path) {
if (!fileExists(path))
return false;
if (!fileIsReadable(file))
return false;
...
return true;
}
Because of that, I'd suggest you follow this practice for try/catch blocks. It also makes it quicker to see what the "expected" return value is.
In regards to the bytecode, then yes, there is indeed a difference. I made a quick sample program
class TryBlock {
public static void main(String[] args) {
a();
b();
}
public static boolean a() {
try {
System.out.println("A");
return true;
} catch (Exception e) {
return false;
}
}
public static boolean b() {
try {
System.out.println("B");
} catch (Exception e) {
return false;
}
return true;
}
}
Then compiled it and inspected the bytecode
$ javac TryBlock.java; javap -c TryBlock
Compiled from "TryBlock.java"
class TryBlock {
TryBlock();
Code:
0: aload_0
// Method java/lang/Object."<init>":()V
1: invokespecial #1
4: return
public static void main(java.lang.String[]);
Code:
// Method a:()Z
0: invokestatic #2
3: pop
// Method b:()Z
4: invokestatic #3
7: pop
8: return
public static boolean a();
Code:
// Field java/lang/System.out:Ljava/io/PrintStream;
0: getstatic #4
// String A
3: ldc #5
// Method java/io/PrintStream.println:(Ljava/lang/String;)V
5: invokevirtual #6
8: iconst_1
9: ireturn
10: astore_0
11: iconst_0
12: ireturn
Exception table:
from to target type
0 9 10 Class java/lang/Exception
public static boolean b();
Code:
// Field java/lang/System.out:Ljava/io/PrintStream;
0: getstatic #4
// String B
3: ldc #8
// Method java/io/PrintStream.println:(Ljava/lang/String;)V
5: invokevirtual #6
8: goto 14
11: astore_0
12: iconst_0
13: ireturn
14: iconst_1
15: ireturn
Exception table:
from to target type
0 8 11 Class java/lang/Exception
}
So is there a performance difference? While I haven't tested, my bet is there won't be anything noticeable. On top of that, this will hardly be the bottleneck of your application.
To me this is more a semantics and readability issue.
If your return true is at the end of the segment outside of the try/catch block, it means this function is supposed to return true value unless anything bad happened in between which interrupts the normal flow.
Instead if the return true is at the end of the try block, it means the function should only return true if all the attempts in the try block succeeded.
This difference in byte code is more or less neglectable; and I agree with @kba this is more a style issue. Many return statement at different places inside deeply embedded if blocks would usually be confusing; so it's a good practice to make your code less complex. I.e.
- Use flat blocks than deep embed where possible
- Carry less state to another code segment and/or an inner
if,forortryblock - Use less state and flow controlling variable
- Use less statement like
returnorgobecause they are more or less a compulsory change of the logic flow.
Hope that helps.
Return is always set false for any type of exception. This may not be the case you will be expecting. May be some of the unexpected exceptions would cause a false value to be returned. So not a good standard way of returning in catch