简体   繁体   English

为数据库类创建通用的“ getColumn”方法(Java)

[英]Create a generic “getColumn” method for a database class (Java)

I have a Database class that encapsulates the functionality of java.sql.* classes. 我有一个数据库类,其中封装了java.sql.*类的功能。 Basically you subclass it in order to create a connection to a particular database, and then you can use its methods to perform common operations. 基本上,您可以将其子类化以创建到特定数据库的连接,然后可以使用其方法执行常见操作。

One operation I'd like to implement is a getColumn() method. 我要实现的一个操作是getColumn()方法。 If the expected database column is a String datatype, I could do the following: 如果期望的数据库列是String数据类型,则可以执行以下操作:

public List<String> getColumn(String sql) throws SQLException
{
    List<String> results = new ArrayList<>();
    ResultSet rs = _stmt.executeQuery(sql);
    while (rs.next())
    {
        results.add(rs.getString(1));
    }
    return results;
}

But I would like to genericize this method with a template parameter, and use the proper ResultSet.get* method to populate the ArrayList . 但是我想使用模板参数来泛化此方法,并使用适当的ResultSet.get*方法填充ArrayList

Something like this: 像这样:

public <T> List<T> getColumn(String sql) throws SQLException
{
    List<T> results = new ArrayList<>();
    ResultSet rs = _stmt.executeQuery(sql);
    while (rs.next())
    {
        // if T is String, do:
        // results.add(rs.getString(1));
        // if T is Integer, do:
        // results.add(rs.getInt(1));
        // etc.
    }
    return results;

I'm sure there must be an elegant way to do this. 我相信必须有一种优雅的方法来做到这一点。 Thoughts? 思考? Am I going about this the wrong way? 我会以错误的方式处理吗? } }

Here's one way of doing it, 这是一种方法,

public <T> List<T> getColumn(String sql) throws SQLException {
    List<T> results = new ArrayList<>();
    ResultSet rs = _stmt.executeQuery(sql);
    while (rs.next()) {
        @SuppressWarnings("unchecked")
        final T colVal = (T) rs.getObject(1);
        results.add(colVal);
    }
    return results;
}

A common mistake is attempting a method with signature like: 一个常见的错误是尝试使用签名这样的方法:

<T> T fn()

In Java there is no way to find out within an invocation of fn what T . 在Java中,无法在fn的调用中找出T The choices are return null , unsafely cast an object that may or may not be a T or throw an exception. 选择返回return null ,不安全地强制转换可能是T或可能不是T的对象或引发异常。 If you have something similar but a return type of List<T> the only thing you could store in that list is null . 如果您有类似的东西,但是返回类型为List<T>则您可以存储在该列表中的唯一内容为null

So what to do. 那么该怎么办。 Typically you would pass in an argument to create the required type. 通常,您将传入一个参数以创建所需的类型。 A function object, for instance. 例如,一个功能对象。 (I would use java.util.function.Function , but checked exceptions get in the way.) (我将使用java.util.function.Function ,但检查的异常会妨碍您。)

List<String> names = getColumn(
    "SELECT [...]",
    (result, column) -> result.getString(column)
);
[...]

interface ResultFunction<T> {
    T get(ResultSet results, int column) throws SQLException;
}

public <T> List<T> getColumn(
    String sql, ResultFunction<T> function
) throws SQLException {
    List<T> values = new ArrayList<>();
    try (ResultSet result = _stmt.executeQuery(sql)) {
        while (result.next()) {
            values.add(function.get(result, 1));
        }
    }
    return values;
}

You may want to expand the functionality of ResultFunction and perhaps use enums. 您可能要扩展ResultFunction的功能,并可能使用枚举。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM