return 在 try 块中 vs return 在块之后

return in try block vs return after the block

我在一个小型静态方法中有一个 try 语句,关于我应该从哪里 return 是否有最佳实践?

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

或之后,

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

在功能上,这些 应该 执行相同,实际上是否存在字节码差异?性能方面,它们 完全 相同吗?

或者只是一个比另一个更受欢迎?哪个以及为什么?

我还没有听说过这方面的实际最佳实践,但是您经常看到当方法使用过早的 returns 时,returns true 的情况是底部,例如

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

  if (!fileIsReadable(file))
    return false;

  ...
  return true;
}

因此,我建议您对 try/catch 个块遵循此做法。它还可以更快地查看 "expected" return 值是什么。

关于字节码,是的,确实有区别。我制作了一个快速示例程序

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
}

所以有性能差异吗?虽然我还没有测试过,但我敢打赌不会有任何明显的变化。最重要的是,这几乎不会成为您应用程序的瓶颈。

对我来说,这更多是语义和可读性问题。

如果你的 return truetry/catch 块之外的段的末尾,这意味着这个函数应该是 return 真值,除非在这两者之间发生了任何不好的事情中断正常流量。

相反,如果 return true 位于 try 块的末尾,则意味着只有在 try 块中的所有尝试都成功时,该函数才应该 return 为真。

这种字节码的差异或多或少可以忽略不计;我同意@kba,这更像是一个风格问题。许多 return 语句在深度嵌入 if 块内的不同位置通常会造成混淆;所以让你的代码不那么复杂是个好习惯。即

  1. 尽可能使用平面块而不是深度嵌入
  2. 将较少的状态携带到另一个代码段and/or内部iffortry
  3. 使用较少的状态和流量控制变量
  4. 少用像returngo这样的语句,因为它们或多或少是逻辑流程的强制性改变。

希望对您有所帮助。

对于任何类型的异常,

Return 始终设置为 false。这可能不是您所期望的情况。可能某些意外异常会导致返回错误值。所以在 catch

中返回不是一个好的标准方式