Java 1.6 中的 try-with-resources 的等效写法

11

我有以下代码:

    public class Main {

        public static void main(String[] args) throws SQLException {

            try (
                    Connection conn = DBUtil.getConnection(DBType.HSQLDB);
                    Statement stmt = conn.createStatement(
                            ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
                    ResultSet rs = stmt.executeQuery("SELECT * FROM tours");
                    ) {

            DBUtil.getConnection();

            } catch (SQLException e) {
                DBUtil.processException(e);
            } 

        }

    }

我使用这段代码从数据库中获取数据。我的问题是我不能使用Java 1.7编译器,而必须使用1.6。如何将try-with-resources代码翻译成1.6可用的代码?在这个特殊的try块中到底发生了什么?


1
将所有括号内的代码放在try代码块的开头,并将所有结束代码放在所有catch之后的finally中。 - AntonH
1
(i) 将语句放在try代码块中。(ii) 在finally块中关闭需要关闭的内容。 - assylias
这么简单吗?好的,我以为try-with-resources更复杂,因为我看到了一些奇怪的帖子。 - schirrmacher
为什么不能使用Java 7编译器?你可以将目标兼容性设置为Java 6... - Duncan Jones
这是一个大学项目,我们应该使用1.6编译器。 - schirrmacher
3个回答

15

Oracle解释了try-with-resources的工作原理,链接在此

简单来说,Java 1.6中没有简单的方法来实现这一点。问题在于异常中缺少“抑制”字段。您可以忽略它,并硬编码当try和close引发不同异常时会发生什么,或者创建自己的异常子类层次结构,该结构具有抑制字段。

在第二种情况下,上面的链接提供了正确的实现方法:

   AutoClose autoClose = new AutoClose();
   MyException myException = null;
   try {
       autoClose.work();
   } catch (MyException e) {
       myException = e;
       throw e;
   } finally {
       if (myException != null) {
           try {
               autoClose.close();
           } catch (Throwable t) {
               myException.addSuppressed(t);
           }
       } else {
           autoClose.close();
       }
   }  

等同于

try (AutoClose autoClose = new AutoClose()) {
    autoClose.work();
}

如果您想简化代码,不想创建大量新的异常类,那么您需要决定在finally语句块中catch子句中抛出什么(t或e)。

附注:上面的链接中还讨论了如何处理try中的多个变量声明。而要正确地实现它所需的代码量惊人。大多数人在Java 1.6中采用缩短finally语句块内异常处理和使用null检查的捷径。


1
我建议使用Apache的commons-dbutils库,其中包含类DBUtilsclosecloseQuietly方法。代码如下:
import org.apache.commons.dbutils.DBUtils;
...
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;

try {
    conn = myOwnUtil.getConnection();
    stmt = conn.createStatement();
    rs = stmt.executeQuery( "SELECT * FROM table" ); // or any other custom query
} catch ( SQLException e ) {
    <<handle exception here>>;
} finally {
    DBUtils.closeQuietly( conn );
    DBUtils.closeQuietly( stmt );
    DBUtils.closeQuietly( rs );
    // or simply use DBUtils.close( conn, stmt, rs );
}

请注意,closeQuietly不会抛出任何异常,而close可能会转换为SQLException,因此请根据自己的用例调整代码。
如果您想关闭流,则可以使用apache的commons-io和IOUtils类,该类还具有close和closeQuietly。

0

像这样做:

Connection conn = null;
Statement stmt = null;
ResultSet rs = null;

try {
    conn = DBUtil.getConnection(DBType.HSQLDB);
    stmt = conn.createStatement(
    ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
    rs = stmt.executeQuery("SELECT * FROM tours");
} catch (SQLException e) {
    DBUtil.processException(e);
} finally {
    if(conn != null) {
        conn.close();
    }
    if(stmt != null) {
        stmt.close();
    }
    if(rs != null) {
        rs.close();
    }
}

2
-1 这与 try-with-resources 不等同。特别是在异常处理方面。 - Duncan Jones
多年的争论之后,我们又回到了起点。只需在Google上搜索“Java 6 close resources”,就会得到很多解释为什么这是不正确的,包括SO的问题。例如,3年前的https://dev59.com/FG025IYBdhLWcg3wzpaK(其中有被接受的答案是“使用JDK 7,它更简单”)。 - Ordous
在 finally 块中不关闭语句需要另一个 try/catch 吗? - Danish ALI

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