gpt4 book ai didi

用于 JDBC 语句执行的 Java 8 lambda 样式包装器

转载 作者:行者123 更新时间:2023-11-30 06:30:20 25 4
gpt4 key购买 nike

我有一些用于 JDBC 语句执行的包装类,其中包含许多方法,如下所示:

public ResultSet executeQuery(String sql) {
try (Statement statement = this.connection.createStatement()) {
return statement.executeQuery(sql);
} catch (SQLException e) {
throw new RuntimeException("My custom statement execution failure", e);
}
}

public int executeUpdate(String sql) {
try (Statement statement = this.connection.createStatement()) {
return statement.executeUpdate(sql);
} catch (SQLException e) {
throw new RuntimeException("My custom statement execution failure", e);
}
}

...

因此有很多方法仅在 1) 返回类型和 2) 实际委托(delegate)方法上有所不同。

我想以 Ruby 的 lambda 方式传递可执行调用,以将样板代码减少为如下所示:

public Boolean executeQuery(String sql) {
return wrapException(s -> {s.executeQuery(sql)});
}

private <T> wrapException(Function<Statement, <T>> query)throws Exception {
try (Statement statement = this.connection.createStatement()) {
return query.apply(statement);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

我目前无法理解的两件事是:

  1. 如何保留wrappedQuery函数的通用返回类型
  2. s.executeQuerty(sql) 仍然提示未处理的 SQLException,如此有效,我无法将所有异常处理都包裹起来

有什么想法吗?

最佳答案

  1. Function<Statement, <T>>不是有效的语法。应该只是Function<Statement, T> 。显然,您将类型参数的声明(例如在方法的开头( <T> ))与类型参数的使用混淆了,类型参数应该是一个简单的名称,例如 T 。 。请注意,可能出于同样的原因,您的方法缺少返回类型。应该有一个<T>声明类型参数,后跟 T在方法名称之前声明返回类型。

  2. 您的方法 wrapException仍然声明throws Exception这比只声明抛出 SQLException 的 JDBC 方法更糟糕。 。这与整个意图相矛盾。

  3. 返回 lambda 表达式的值应该遵循表达式语法,
    喜欢 s -> s.executeQuery(sql) ,或包含 return声明,例如s -> { return s.executeQuery(sql); } 。你的表情s -> {s.executeQuery(sql)}是不完整(缺少分号)的语句语法,没有 return 。另外,您正在声明 Boolean尽管如此,返回类型 executeQuery返回 ResultSet .

  4. 功能界面 java.util.function.Function 声明函数方法 apply 它没有声明任何已检查的异常,因此您无法通过 lambda 表达式来实现它,该表达式可能会抛出像 SQLException 这样的已检查的异常。因此,对于您的用例,您需要不同的功能接口(interface)。

    您可以将异常类型设置为通用,以允许您的自定义功能接口(interface)在您需要 Function 的其他地方重用。这可能会引发特定的异常。例如

    public interface ThrowingFunction<T,R,E extends Exception> {
    R apply(T input) throws E;
    }

有了这个,你就可以声明

public ResultSet executeQuery(String sql) {
return wrapException(s -> s.executeQuery(sql));
}
public int executeUpdate(String sql) {
return wrapException(s -> s.executeUpdate(sql));
}
private <T> T wrapException(ThrowingFunction<Statement, T, SQLException> operation) {
try(Statement statement = this.connection.createStatement()) {
return operation.apply(statement);
} catch(SQLException e) {
throw new RuntimeException(e);
}
}
<小时/>

但请注意,存在一个与泛型/lambda 用法无关的一般问题,该问题也适用于您的原始代码:

Statement.close()

Note: When a Statement object is closed, its current ResultSet object, if one exists, is also closed.

try(…)的全部目的语句是为了确保资源在离开 block 时会立即关闭,因此返回 ResultSet从那里开始是没有意义的。 (但这不适用于executeUpdate)。解决此问题的一种方法是传递一个函数来处理 ResultSet就在区 block 内。

public <R> R executeQuery(String sql, ThrowingFunction<ResultSet,R,SQLException> op) {
return wrapException(s -> op.apply(s.executeQuery(sql)));
}

这允许函数返回任意值,而不依赖于 ResultSet不再,例如

String value = executeQuery("SELECT STRING_COL FROM SOME_TABLE WHERE ID=42",
rs -> rs.next()? rs.getString(1): null);
int max = executeQuery("SELECT MAX(INTVAL_COL) FROM SOME_TABLE",
rs -> rs.next()? rs.getInt(1): -1);

关于用于 JDBC 语句执行的 Java 8 lambda 样式包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46292402/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com