在try块中return与在块后return的区别

8

我在一个小的静态方法中使用了try语句,那么最佳实践是从哪里返回呢?

try {
    mightThrow();
    return true;
} catch (Exception e) {
    return false;
}

或者之后,
try {
    mightThrow();
} catch (Exception e) {
    return false;
}
return true;

就功能而言,这些应该是相同的,但实际上是否有字节码的差异呢?就性能而言,它们是完全相同的吗?

还是其中一个比另一个更受欢迎?哪个更好?为什么?


4
有字节码上的区别吗?为什么不检查一下字节码呢? - Dioxin
3个回答

8

我没有听说过这个问题的最佳实践,但通常情况下,当方法使用过早返回时,返回 true 的情况在底部,例如:

public bool canReadFile(path) {
  if (!fileExists(path))  
    return false;

  if (!fileIsReadable(file))
    return false;

  ...
  return true;
}

因此,我建议您遵循以下的try/catch块实践。这也使得更快地看到“预期”的返回值。
关于字节码,确实有所不同。我制作了一个快速的示例程序。
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;
    }

}

然后编译它并检查字节码

$ 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
}

那么性能有差别吗?虽然我没有测试,但我敢打赌不会有什么明显的差别。此外,这几乎不会成为您应用程序的瓶颈。


很棒的回答。有一个问题:你是如何编译和检查字节码的? - rhitz
3
就我回答所述,我使用了javac后跟着javap - kba

2
对我来说,这更多是一个语义和可读性问题。
如果你的`return true`在段落结尾并且在`try/catch`块之外,意味着该函数应该返回真值,除非在此期间发生了任何中断正常流程的错误。
相反,如果`return true`在`try`块的结尾处,则意味着该函数仅在`try`块中的所有尝试都成功时才返回真值。
字节码上的这种差异或多或少可以忽略不计;我同意@kba的观点,这更多是一个风格问题。通常,在深度嵌套的`if`块内使用许多不同位置的`return`语句通常会令人困惑;因此,将代码简化是一个好习惯。例如:
  1. 尽可能使用平坦的块而不是深嵌套的块
  2. 在另一个代码段和/或内部的`if`、`for`或`try`块中携带较少的状态
  3. 使用较少的状态和流控制变量
  4. 使用较少的语句,如`return`或`go`,因为它们或多或少是一种强制改变逻辑流程。
希望能对您有所帮助。

0

对于任何类型的异常,返回值总是设置为false。这可能不是您所期望的情况。也许一些意外的异常会导致返回false值。因此,在catch中返回值并不是一个好的标准方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接