Перевірка значення null int від Java ResultSet


277

У 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");
  }
}

З наведеного вище фрагмента коду, чи є кращий спосіб зробити це, і я припускаю, що другий тест бувNull () є зайвим?

Навчіть нас і дякую


14
Я знайшов це запитання, оскільки в базі даних є нульовий стовпчик, і він представлений Integer на Java. Ви можете подумати, що наявність нульового числового стовпця в базі даних буде досить поширеним, щоб API ResultSet вмістив його трохи елегантніше.
spaaarky21

Я не відправляю це як відповідь , тому що це тангенціальний і далеко не універсальна: Моє звичайне рішення це поставити IF(colName = NULL, 0, colName) AS colNameв SELECTзаяві (переважно в збережена процедура). По-філософськи це зводиться до того, чи повинен БД відповідати додатку, чи навпаки. Оскільки SQL обробляє NULL легко, і багато споживачів SQL цього не роблять (тобто java.sql.ResultSet), я вирішую обробляти його в БД, коли це можливо. (Це, звичайно, передбачає, що концептуально NULL і нуль еквівалентні вашим цілям.)
s.co.tt

Відповіді:


368

За замовчуванням, 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
Я щойно знайшов те саме твердження в документах. Варто окремої нитки на SO imho. ( java.sun.com/j2se/1.4.2/docs/api/java/sql/… )
Роман

6
@Roman - дивіться javadoc для getInt в ResultSet: "Повертає: значення стовпця; якщо значення SQL NULL, повернене значення дорівнює 0"
Cowan

150
Правда, справді, смішна. getInt()повинен бути, getInteger()який повертає значення Integer, тобто nullякщо є значення БД null. Дияволи справді зіпсували це.
ривантаж

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не обов'язково повертає цілий ряд, через характер типу стовпця у dc oracle, який я використовую ("Number").
Метт Мак-

Та ж проблема Метта ... З MySQL і Types.BIGINT(що має бути відображено в a Long) getObject()метод повертає 0 замість null.
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");

1
Ні, але він сконструює непотрібний об'єкт Integer у ненульовому випадку. (І BTW більшість драйверів JDBC взагалі не потрапляють на db під час будь-яких дзвінків методу ResultSet ... як правило, ви не отримаєте ResultSet до тих пір, поки всі дані не потраплять за провід).
EricS

Це залежить від розміру вибору. У більшості драйверів за замовчуванням дорівнює 10 рядків, і коли вилучення буде завантажено, вони будуть оброблені, але наступний вибор не буде отриманий, поки обробка не буде закінчена.
Kristo Aun

Я здивований, що ваша відповідь не є кращою відповіддю :-) Я голосую, тому що саме правильна відповідь уникає дуже хитро небезпечного методу wasNull (). Для мене це додаткова причина припинити використання Java ;-) і продовжувати користуватися VB.Net, де RecordSet вирішив цю просту проблему вже більше 10 років!
шлебе

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) не повертає 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
}

Раді отримати відгуки


2

Ви можете викликати цей метод, використовуючи resultSet та ім'я стовпця, що має тип номера. Він поверне ціле число, або нульове значення. Не буде повернено нулі для порожнього значення в базі даних

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

Чи можете ви, будь ласка, детальніше розповісти про те, як це вирішує питання?
Стерлінг Арчер

Ви можете викликати цей метод, використовуючи resultSet та ім'я стовпця, що має тип номера. Він поверне ціле число, або нульове значення. Не буде повернено нулі для порожнього значення в базі даних.
amine kriaa

Відмінно! Відредагуйте це у своїй відповіді (і видаліть коментар після редагування), і ви отримаєте хорошу відповідь :)
Стерлінг Арчер

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, якщо вона визначена як нульова, має набір значень, що складається з додатних чисел, нуля, від’ємних чисел та NULL. У будь-який момент часу можна просто вставити дійсний рядок даних, що містить це магічне число, і раптом все піде погано. Це, в основному, реалізація магічного числа анти шаблону. Не робіть цього.
Маттіас Гринішак
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.