Перевірка значення 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.