【问题标题】:How does return work in try, catch, finally in Java?在 Java 中,try、catch 和 finally 中的 return 是如何工作的?
【发布时间】:2018-12-04 19:44:19
【问题描述】:

我无法确切了解returntrycatch 中的工作原理。

  • 如果我有tryfinally 而没有catch,我可以将return 放在try 块内。
  • 如果我有trycatchfinally,我不能将return 放在try 块中。
  • 如果我有 catch 块,我必须将 return 放在 trycatchfinally 块之外。
  • 如果我删除catch 块和throw Exception,我可以将return 放入try 块中。

它们究竟是如何工作的?为什么我不能将return 放在try 块中?

带有trycatchfinally的代码

 public int insertUser(UserBean user) {
     int status = 0;

     Connection myConn = null;
     PreparedStatement myStmt = null;

     try {
         // Get database connection
         myConn = dataSource.getConnection();

         // Create SQL query for insert
         String sql = "INSERT INTO user "
                    + "(user_name, name, password) "
                    + "VALUES (?, ?, ?)";

         myStmt = myConn.prepareStatement(sql);

         // Set the parameter values for the student
         myStmt.setString(1, user.getUsername());
         myStmt.setString(2, user.getName());
         myStmt.setString(3, user.getPassword());

         // Execute SQL insert
         myStmt.execute();
     } catch (Exception exc) {
         System.out.println(exc);
     } finally {
         // Clean up JDBC objects
         close(myConn, myStmt, null);
     }

     return status;
 }

带有tryfinally 不带catch 的代码

 public int insertUser(UserBean user) throws Exception {
     int status = 0;

     Connection myConn = null;
     PreparedStatement myStmt = null;

     try {
         // Get database connection
         myConn = dataSource.getConnection();

         // Create SQL query for insert
         String sql = "INSERT INTO user "
                    + "(user_name, name, password) "
                    + "VALUES (?, ?, ?)";

         myStmt = myConn.prepareStatement(sql);

         // Set the parameter values for the student
         myStmt.setString(1, user.getUsername());
         myStmt.setString(2, user.getName());
         myStmt.setString(3, user.getPassword());

         // Execute SQL insert
         myStmt.execute();

         return status;
     } finally {
         // Clean up JDBC objects
         close(myConn, myStmt, null);
     }
 }

【问题讨论】:

  • 这就是为什么在try-catchtry-catch-finally 中包含return 是一个糟糕的设计。考虑this 问题。
  • IMO,在 try 块中返回是完全正常的,但您需要确保在 all catch 块中返回一些东西。除此之外,请注意 Bathsheba mentioned 的内容。这本质上是关于单一退出点的相同辩论 - 在 if 块中返回是否不好。
  • @soufrk 不,这显然不是糟糕的设计。如果您返回范围在try 块内的内容,请务必从try 内部返回。 不要扩大你想要返回的变量的范围。 将是糟糕的设计(使范围尽可能小)。
  • @soufrk 如果你没有从 try 或 catch 中返回,它 finally 语句是没有用的。这就是它存在的原因,因此 Java 不需要 goto 进行清理。不过,我想不出一个很好的理由从最后回来。我认为这是语言设计中的错误。

标签: java return try-catch


【解决方案1】:

是的,这令人困惑。

在 Java 中,非void 函数的所有程序控制路径必须return 结束,否则会引发异常。这条规则说得很好,很简单。

但是,令人厌恶的是,Java 允许您在finally 块中放置一个额外 return,它会覆盖之前遇到的任何return

try {
    return foo; // This is evaluated...
} finally {
    return bar; // ...and so is this one, and the previous `return` is discarded
}

【讨论】:

  • “覆盖之前遇到的任何返回”或抛出。
  • @AndyTurner:虽然第二点没那么离谱;-)
  • 在我看来,从 finally 子句中抛出异常确实是一种反模式,正是因为这个原因。
  • 所以你可以在调试时使用try { return something_with_side_effects(); }finally { return bar;} 来避免额外的混乱?! :-D
  • @Prof.Falken 现在我有一种尝试try { return i++; } finally { return i++; } 的冲动,即使写了这个评论我也觉得很脏......
【解决方案2】:

Finally 块将始终执行,即使我们在 catch 块 中捕获了异常,甚至我们的 try 块 已按预期执行。

那么finally块什么时候会在流程中执行...

如果我们在 try/catch 块中有 return 语句,那么在执行 return 语句之前 finally 块 将被执行(如关闭连接或 I/O)

function returnType process() {
  try {
      // some other statements
      // before returning someValue, finally block will be executed
      return someValue;
  } catch(Exception ex) {
     // some error logger statements
     // before returning someError, finally block will be executed
     return someError;
  } finally {
    // some connection/IO closing statements
    // if we have return inside the finally block
    // then it will override the return statement of try/catch block
    return overrideTryCatchValue;
  }
}

但如果您在 finally 语句中有 return 语句,那么它将在 try 或 catch 块中覆盖 return 语句

【讨论】:

  • 完美答案@Pramesh
【解决方案3】:

如果我有 try, catch,最后我不能把 return 放在 try 块中。

你绝对可以。您只需要确保方法中的每个控制路径都正确终止。我的意思是:通过你的方法的每条执行路径要么以return结尾,要么以throw结尾。

例如,以下工作:

int foo() throws Exception { … }

int bar() throws Exception {
    try {
        final int i = foo();
        return i;
    } catch (Exception e) {
        System.out.println(e);
        throw e;
    } finally {
        System.out.println("finally");
    }
}

在这里,您有两种可能的执行路径:

  1. final int i = foo()
  2. 要么
    1. System.out.println("finally")
    2. return i
    1. System.out.println(e)
    2. System.out.println("finally")
    3. throw e

如果foo 没有抛出异常,则采用路径 (1, 2)。如果抛出异常,则采用路径 (1, 3)。请注意,在这两种情况下,finally 块是如何在离开方法之前执行的。

【讨论】:

  • +1 从技术上讲,“您只需要确保方法中的每个控制路径都正确终止”,编译器会为您执行此操作,有时过于热心。
【解决方案4】:

这是涉及异常处理时的正常程序流程。在代码中包含 catch 块会创建代码路径可以直接跳转到 catch 块的情况。这违背了在返回某些内容的方法中具有 return 语句的要求。如果发生异常,return 语句可能不会被执行,因此编译器会抛出错误。因此,为避免此问题,您需要在方法中至少再添加 1 个 return 语句。

如果你在 try-finally 块中添加了 return 语句并且你没有 catch 块,那没关系。这里没有出现代码路径异常的情况。

如果您在 try 块中添加了 return 语句并且您有 catch 块,那么您可以在 catch 块中或在方法的末尾添加 return。

如果您在 try 块中添加了 return 语句并且您有 catch 块和 finally 块,那么您可以在 catch 块中或在方法的末尾添加 return。您也可以选择在 finally 块中添加 return。如果您使用的是 eclipse,它会生成一个警告,可以使用上面的方法定义来抑制 -

@SuppressWarnings("finally")

【讨论】:

  • 默认情况下不会发出警告 JDK javac 运行。它被发布,例如在 Eclipse 中,如果相应的首选项复选框被激活(这是默认情况)。
【解决方案5】:

我想这就是你要问的:

如果我有 try, catch,最后我不能把 return 放在 try 块中。

所以如果你添加一个catch 块,你不能在try 块中放置一个return

问题是如果你添加一个catch 然后控制drops through 并且你需要一个return 在方法的末尾或者它是一个语法错误。我尚未对此进行测试,但我假设您可以try 块中添加一个 return,但您还必须在 catch 内或在方法的末尾添加一个就像你现在一样。

【讨论】:

  • 你绝对可以在 try 块中放一个 return。 -1
  • 呃,我就是这么说的。 @UKMonkey
  • “所以如果你添加了一个catch块,你就不能在try块里放一个return。”不,不是你说的。
  • "你可以在 try 块中放一个 return,但你还必须像现在一样在 catch 内或方法的末尾添加一个。"我只是指出 OP 出了什么问题。 @UKMonkey
【解决方案6】:

在第二个示例中,如果发生检查的异常,则它会移交给调用方法。

在第一个例子中,如果发生检查的异常,那么它在同一个方法中处理,因为catch块负责处理异常。

如果您在 catch 块中编写 return 语句,那么它会起作用。
即,

try{  
    return ..  
}catch(Exception e){  
    return ..  
}finally{  
}

但这不是好的编程习惯。

【讨论】:

  • “但这不是好的编程习惯。” ——你需要证明这种说法是正确的。既然我不同意,我会对此很好奇。
【解决方案7】:

当使用除 void 函数之外的公共函数时,你应该返回一些东西,否则你的函数不会。

【讨论】:

    猜你喜欢
    • 2012-05-26
    • 2012-11-12
    • 1970-01-01
    • 2011-10-31
    • 2020-01-24
    • 1970-01-01
    • 2015-09-05
    • 2011-11-17
    • 2013-02-19
    相关资源
    最近更新 更多