Проверка на нулевое значение int из Java ResultSet

278

В 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 () является избыточным?

Просветите нас и спасибо

ian_scho
источник
14
Я нашел этот вопрос, потому что у меня в базе данных есть обнуляемый столбец, и он представлен целым числом в Java. Можно подумать, что наличие в базе данных пустого числового столбца будет достаточно распространенным, чтобы ResultSet API разместил его немного более элегантно.
spaaarky21
Я не отправляю это как ответ , потому что это тангенциальный и далеко не универсальна: Мое обычное решение это поставить IF(colName = NULL, 0, colName) AS colNameв SELECTзаявлении (предпочтительно в хранимая процедура). С философской точки зрения это сводится к тому, должна ли БД соответствовать приложению или наоборот. Поскольку SQL легко обрабатывает значения NULL, а многие потребители SQL этого не делают (то есть java.sql.ResultSet), я по возможности использую его в БД. (Это, конечно, предполагает, что концептуально NULL и ноль эквивалентны для ваших целей.)
s.co.tt

Ответы:

369

Значение по умолчанию для ResultSet.getIntполя NULLдолжна возвращаться 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 ниже; написанный OP-код не будет компилироваться, поскольку iValне инициализирован)

Ричард
источник
2
Я только что нашел то же утверждение в документах. Стоит отдельная тема по ТАК имхо. ( Java.sun.com/j2se/1.4.2/docs/api/java/sql/... )
Роман
6
@Roman - см. Javadoc для getInt в ResultSet: «Возвращает: значение столбца; если значение равно SQL NULL, возвращаемое значение равно 0»
Коуэн
150
Правда, это действительно смешно. getInt()должно быть, getInteger()которое возвращает, Integerчто, nullесли значение БД null. Разработчики действительно испортили это.
'20
7
@sactiw, следуя этой логике, все на java должно было быть разработано, чтобы избежать NPE, а это не так. Избегать NPE - ответственность разработчиков приложений, а не языка внутреннего API.
Матеус Викари
10
OMG Почему, просто не возвращает NULL, 0и NULLэто две большие разные вещи
deFreitas
84

Другое решение:

public class DaoTools {
    static public Integer getInteger(ResultSet rs, String strColName) throws SQLException {
        int nValue = rs.getInt(strColName);
        return rs.wasNull() ? null : nValue;
    }
}
Патрис ИМБЕРТ
источник
27

Я думаю, это излишне. 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
  }      
}
Андреас Долк
источник
5
Хм, по крайней мере, в моем случае проблема заключается в том, что вызов getObjectне обязательно возвращает целое число, из-за природы типа столбца в оракуле, который я использую («Число»).
Мэтт Мак
Та же проблема с Мэттом ... С MySQL и Types.BIGINT(что должно быть сопоставлено с a Long) getObject()метод возвращает 0 вместо нуля.
xonya
2
Могли бы и сделатьrs.getObject("ID_PARENT", Integer.class)
Арло
26

Просто проверьте, используется ли поле nullили нет ResultSet#getObject(). Замените -1на любое значение с нулевым регистром, которое вы хотите.

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

Или, если вы можете гарантировать, что используете правильный тип столбца БД, так что он ResultSet#getObject()действительно возвращает Integer(и, следовательно, нет Long, Shortили Byte), то вы также можете просто привести его к типу Integer.

Integer foo = (Integer) resultSet.getObject("foo");
BalusC
источник
1
Нет, но он будет создавать ненужный объект Integer в ненулевом случае. (И, кстати, большинство драйверов JDBC вообще не попадают в базу данных во время вызовов методов ResultSet ... обычно ResultSet не возвращается, пока все данные не будут переданы по проводам).
EricS
Это зависит от размера выборки. В большинстве драйверов по умолчанию используется 10 строк, и после извлечения выборки они будут обработаны, но следующая выборка не будет извлечена до тех пор, пока обработка не будет завершена.
Кристо Аун
Я удивлен, что ваш ответ не лучший ответ :-) Я голосую, потому что это правильный ответ, который позволяет избежать очень хитрого небезопасного метода wasNull (). Для меня это дополнительная причина прекратить использовать Java ;-) и продолжать использовать VB.Net, где RecordSet решает эту простую проблему уже более 10 лет!
Schlebe
11

AFAIK вы можете просто использовать

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

даже если это NULL.

Питер Тиллеманс
источник
5

Просто обновление с использованием Java Generics.

Вы можете создать служебный метод для извлечения необязательного значения любого типа Java из заданного ResultSet, ранее приведенного.

К сожалению, getObject (columnName, Class) не возвращает ноль, но значение по умолчанию для данного типа 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
}

Рад получить обратную связь

luchoct
источник
2

Вы можете вызвать этот метод, используя resultSet и имя столбца с типом Number. Он либо возвратит целочисленное значение, либо ноль. Там не будет нулей, возвращаемых для пустого значения в базе данных

private Integer getIntWithNullCheck(ResultSet rset, String columnName) {
    try {
        Integer value = rset.getInt(columnName);
        return rset.wasNull() ? null : value;
    } catch (Exception e) {
        return null;
    }
}
амин криаа
источник
Не могли бы вы рассказать подробнее о том, как это решает вопрос?
Стерлинг Арчер
Вы можете вызвать этот метод, используя resultSet и имя столбца с типом Number. Он либо возвратит целочисленное значение, либо ноль. Там не будет нулей, возвращаемых для пустого значения в базе данных.
amine kriaa
Превосходно! Отредактируйте это в своем ответе (и удалите комментарий после редактирования), и вы получите хороший ответ :)
Sterling Archer
1

С Java 8 вы можете сделать это:

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

В этом случае вы гарантируете, что nVal будет нулевым (а не нулевым), если значение SQL равно NULL

Джордж
источник
2
но не относится кresultSet.getInt("col_name")
rapt
1
С источником данных MSSQL это, похоже, не работает. Требуется дополнительная проверкаif (rs.wasNull())
alltej
1

Для удобства вы можете создать класс-оболочку вокруг 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;
    }

    // ...

}
Джейкоб Крофтс
источник
-6

Еще один хороший способ проверить, если у вас есть контроль над SQL, это добавить значение по умолчанию в самом запросе для вашего столбца int. Тогда просто проверьте это значение.

например, для базы данных Oracle, используйте NVL

SELECT NVL(ID_PARENT, -999) FROM TABLE_NAME;

затем проверьте

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

Конечно, это также при условии, что есть значение, которое обычно не будет найдено в столбце.

Крис
источник
12
Я проголосовал за этот ответ, так как он может вызвать проблемы у многих людей. Столбец int, если он определен как nullable, имеет набор значений, состоящих из положительных чисел, нуля, отрицательных чисел и NULL. В любой момент времени можно просто вставить действительный ряд данных, содержащий это магическое число, и все внезапные вещи испортятся. Это в основном реализация анти-паттерна магического числа. Не делай этого.
Матиас Гринишак