检查Java ResultSet中的null int值

在Java中,我试图测试一个空值,从ResultSet,其中列被强制转换为基本int类型。

int iVal;
ResultSet rs = magicallyAppearingStmt.executeQuery(query);
if (rs.next()) {
if (rs.getObject("ID_PARENT") != null && !rs.wasNull()) {
iVal = rs.getInt("ID_PARENT");
}
}

从上面的代码片段中,是否有更好的方法来做到这一点,并且我假设第二个wasNull ()测试是多余的?

教育我们,谢谢

306948 次浏览

当字段值为NULL时,ResultSet.getInt的默认值是返回0,这也是你的iVal声明的默认值。在这种情况下,您的测试是完全多余的。

如果你真的想做一些不同的事情,如果字段值为NULL,我建议:

int iVal = 0;
ResultSet rs = magicallyAppearingStmt.executeQuery(query);
if (rs.next()) {
iVal = rs.getInt("ID_PARENT");
if (rs.wasNull()) {
// handle NULL field value
}
}

(编辑如下@martin评论;因为iVal没有初始化,所以写的OP代码不会被编译)

我认为这是多余的。rs.getObject("ID_PARENT")应该返回一个Integer对象或null,如果列值实际上是NULL。所以它甚至可以这样做:

if (rs.next()) {
Integer idParent = (Integer) rs.getObject("ID_PARENT");
if (idParent != null) {
iVal = idParent; // works for Java 1.5+
} else {
// handle this case
}
}

我想你可以简单地使用

iVal = rs.getInt("ID_PARENT");
if (rs.wasNull()) {
// do somthing interesting to handle this situation
}

即使它是NULL。

另一种很好的检查方法是,如果您控制了SQL,则在查询本身中为int列添加一个默认值。然后检查这个值。

例如,对于Oracle数据库,使用NVL

SELECT NVL(ID_PARENT, -999) FROM TABLE_NAME;

然后检查

if (rs.getInt('ID_PARENT') != -999)
{
}

当然,这也是在假设有一个值通常不会在列中找到的前提下。

另一个解决方案:

public class DaoTools {
static public Integer getInteger(ResultSet rs, String strColName) throws SQLException {
int nValue = rs.getInt(strColName);
return rs.wasNull() ? null : nValue;
}
}

只需检查字段是否为null或没有使用ResultSet#getObject()。用你想要的任何空值替换-1

int foo = resultSet.getObject("foo") != null ? resultSet.getInt("foo") : -1;

或者,如果你能保证使用正确的DB列类型,从而ResultSet#getObject()真正返回Integer(而不是LongShortByte),那么你也可以将其类型转换为Integer

Integer foo = (Integer) resultSet.getObject("foo");

使用java 8,你可以这样做:

Long nVal = Optional.ofNullable(resultSet.getBigDecimal("col_name"))
.map(BigDecimal::longValue).orElse(null));

在这种情况下,如果SQL值为null,则确保nVal将为null(而不是零)

为了方便起见,你可以创建一个ResultSet的包装器类,当ResultSet通常不会返回空值时,它会返回空值。

public final class ResultSetWrapper {


private final ResultSet rs;


public ResultSetWrapper(ResultSet rs) {
this.rs = rs;
}


public ResultSet getResultSet() {
return rs;
}


public Boolean getBoolean(String label) throws SQLException {
final boolean b = rs.getBoolean(label);
if (rs.wasNull()) {
return null;
}
return b;
}


public Byte getByte(String label) throws SQLException {
final byte b = rs.getByte(label);
if (rs.wasNull()) {
return null;
}
return b;
}


// ...


}

只是Java泛型的更新。

您可以创建一个实用程序方法,从给定的ResultSet(先前强制转换的结果集)检索任意Java类型的可选值。

不幸的是,getObject(columnName, Class)不返回null,而是给定Java类型的默认值,因此需要2次调用

public <T> T getOptionalValue(final ResultSet rs, final String columnName, final Class<T> clazz) throws SQLException {
final T value = rs.getObject(columnName, clazz);
return rs.wasNull() ? null : value;
}

在这个例子中,你的代码如下所示:

final Integer columnValue = getOptionalValue(rs, Integer.class);
if (columnValue == null) {
//null handling
} else {
//use int value of columnValue with autoboxing
}

乐于得到反馈

您可以使用resultSet和具有Number类型的列名调用此方法。它将返回Integer值或null。数据库中的空值将不会返回零

private Integer getIntWithNullCheck(ResultSet rset, String columnName) {
try {
Integer value = rset.getInt(columnName);
return rset.wasNull() ? null : value;
} catch (Exception e) {
return null;
}
}

以防有人在Kotlin编程时来到这里(就像我一样),BalusC建议的答案可以很好地工作。要注意的是,ShortFloatResultSet内部分别被实例化为IntegerDouble,在调用getObject()之后,我们应该将它们强制转换为正确的类型。在我的案例中,最终代码是:

when {
propKClass.isSubclassOf(Int::class) -> rs.getObject(colName) as Int?
propKClass.isSubclassOf(Short::class) -> (rs.getObject(colName) as Int?)?.toShort()
propKClass.isSubclassOf(Long::class) -> rs.getObject(colName) as Long?
propKClass.isSubclassOf(Boolean::class) -> rs.getObject(colName) as Boolean?
propKClass.isSubclassOf(Double::class) -> rs.getObject(colName) as Double?
propKClass.isSubclassOf(Float::class) -> (rs.getObject(colName) as Double?)?.toFloat()
else -> rs.getString(colName)
}

如果你想要调用ResultSet.wasNull()的替代方法,你可以使用getObject()并强制转换为正确的类型。

Long val = (Long)rs.getObject(pos++);

你也可以用setObject()Statement中设置空值。

pstmt.setObject(pos++, null);

在Kotlin中,我只会解决它一次,并永远解决这个问题:

fun <K : Any> ResultSet.getNullable(columnLabel: String, type: KClass<K>): K? =
this.getObject(columnLabel, type.java)

之后你可以这样做:

rs.getNullable("ID_PARENT", Int::class)

我想如果你愿意,你也可以这样做

fun <K> ResultSet.getNullable(columnLabel: String, type: Class<K>): K? =
this.getObject(columnLabel, type)

所以你可以这样做:

rs.getNullable("ID_PARENT", Int::class.java)

最好仍然使这两种方法可用,如果你碰巧与开发人员不能就甚至最简单的事情达成一致意见。

fun <K : Any> ResultSet.getNullable(columnLabel: String, type: KClass<K>): K? =
this.getNullable(columnLabel, type.java)


fun <K> ResultSet.getNullable(columnLabel: String, type: Class<K>): K? =
this.getObject(columnLabel, type)

编辑:如果库仍然是挑剔的,你终于可以这样做:

rs.getNullable("ID_PARENT", String::class)?.let {FOO.valueOf(it) }