有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java相对于返回,Finally块何时运行

我昨天偶然发现了一个有趣的错误,并且已经修复了它,但是今天早上它仍然困扰着我,所以我想看看是否有人可以解释一下这个问题

有关守则:

final ResultSet rs = prepStatement.executeQuery();
try
{
   if (!rs.next())
   {
      throw new IllegalStateException("Expected non-empty result");
   }
   return rs.getInt(0 + 1);
}
finally
{
   rs.close();
}

现在来看看从那以后再也没有出现过的部分。每隔一段时间,return语句就会抛出一个异常,指示已对关闭的ResultSet调用了getInt(int)。我验证了代码中的任何地方都没有关闭准备好的语句,如果数据库正在关闭,我还会看到其他错误。这使我相信,有时,finally块会在return语句之前执行。我能想到的唯一一件事是热点编译器并不总是正确的。我正在使用下面列出的Oracle JVM

java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

我想我应该提到的是,我已经看到了许多关于这个订单的其他问题,但它们似乎都表明这是一成不变的,我似乎看到了一些不同的东西

Try-catch-finally-return clarification
https://stackoverflow.com/questions/20164755/the-order-of-invoking-finally-block
Does finally always execute in Java?


共 (1) 个答案

  1. # 1 楼答案

    我编写并编译了下面的课程

    public class Examples {
        public int answer(PreparedStatement prepStatement) throws SQLException {
            final ResultSet rs = prepStatement.executeQuery();
            try {
                if (!rs.next()) {
                    throw new IllegalStateException("Expected non-empty result");
                }
                return rs.getInt(1);
            } finally {
                rs.close();
            }
        }
    }
    

    使用以下命令

    [s_delima@ml-l-sotiriosd Downloads]$ java -version
    java version "1.7.0_45"
    Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
    Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
    [s_delima@ml-l-sotiriosd Downloads]$ javac Examples.java 
    [s_delima@ml-l-sotiriosd Downloads]$ /usr/java/latest/bin/javap -c Examples
    Compiled from "Examples.java"
    public class Examples {
      public Examples();
        Code:
           0: aload_0       
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return        
    
      public int answer(java.sql.PreparedStatement) throws java.sql.SQLException;
        Code:
           0: aload_1       
           1: invokeinterface #2,  1            // InterfaceMethod java/sql/PreparedStatement.executeQuery:()Ljava/sql/ResultSet;
           6: astore_2      
           7: aload_2       
           8: invokeinterface #3,  1            // InterfaceMethod java/sql/ResultSet.next:()Z
          13: ifne          26
          16: new           #4                  // class java/lang/IllegalStateException
          19: dup           
          20: ldc           #5                  // String Expected non-empty result
          22: invokespecial #6                  // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
          25: athrow        
          26: aload_2       
          27: iconst_1      
          28: invokeinterface #7,  2            // InterfaceMethod java/sql/ResultSet.getInt:(I)I
          33: istore_3      
          34: aload_2       
          35: invokeinterface #8,  1            // InterfaceMethod java/sql/ResultSet.close:()V
          40: iload_3       
          41: ireturn       
          42: astore        4
          44: aload_2       
          45: invokeinterface #8,  1            // InterfaceMethod java/sql/ResultSet.close:()V
          50: aload         4
          52: athrow        
        Exception table:
           from    to  target type
               7    34    42   any
              42    44    42   any
    }
    

    如果跟随byte code instructions,您将看到在28调用rs.getInt(1),其值存储在33。在35处调用rs.close()。存储值在40检索,并在41返回

    您所经历的必须来自代码中的其他点