Memeriksa nilai int nol dari Java ResultSet


277

Di Jawa saya mencoba untuk menguji nilai nol, dari ResultSet, di mana kolom sedang dilemparkan ke tipe int primitif .

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

Dari fragmen kode di atas, apakah ada cara yang lebih baik untuk melakukan ini, dan saya berasumsi bahwa tes wasNull () kedua adalah mubazir?

Mendidik kami, dan Terima kasih


14
Saya menemukan pertanyaan ini karena saya memiliki kolom nullable dalam database dan diwakili oleh Integer di Jawa. Anda akan berpikir bahwa memiliki kolom numerik yang dapat dibatalkan dalam basis data akan cukup umum sehingga API ResultSet akan menampungnya sedikit lebih elegan.
spaaarky21

Saya tidak posting ini sebagai jawaban karena tangensial dan jauh dari universal: Solusi saya biasa untuk ini adalah untuk menempatkan IF(colName = NULL, 0, colName) AS colNamedalam SELECTpernyataan (lebih disukai di proc disimpan). Secara filosofis ini bermuara pada apakah DB harus sesuai dengan aplikasi, atau sebaliknya. Karena SQL menangani NULL dengan mudah dan banyak konsumen SQL tidak (yaitu java.sql.ResultSet), saya memilih untuk menanganinya di DB jika memungkinkan. (Ini, tentu saja, mengasumsikan bahwa secara konsep NULL dan nol adalah ekuivalen untuk keperluan Anda.)
s.co.tt

Jawaban:


368

Default untuk ResultSet.getIntketika nilai bidang NULLadalah kembali 0, yang juga merupakan nilai default untuk iValdeklarasi Anda . Dalam hal ini tes Anda benar-benar berlebihan.

Jika Anda benar-benar ingin melakukan sesuatu yang berbeda jika nilai bidangnya NULL, saya sarankan:

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

(Diedit sebagai komentar @martin di bawah ini; kode OP yang ditulis tidak akan dikompilasi karena iValtidak diinisialisasi)


2
Saya baru saja menemukan pernyataan yang sama dalam dokumen. Layak utas terpisah di SO imho. ( java.sun.com/j2se/1.4.2/docs/api/java/sql/… )
Roman

6
@ Roman - lihat javadoc untuk getInt di ResultSet: "Pengembalian: nilai kolom; jika nilainya SQL NULL, nilai yang dikembalikan adalah 0"
Cowan

150
Kebenarannya memang konyol. getInt()seharusnya getInteger()yang mengembalikan Integeritu adalah nulljika nilai DB adalah null. Para devs benar-benar mengacaukan yang satu ini.
ryvantage

7
@sactiw mengikuti logika ini, semua yang ada di java seharusnya dikembangkan untuk menghindari NPE, yang bukan itu masalahnya. Menghindari NPE adalah tanggung jawab pengembang aplikasi, bukan API internal bahasa.
Mateus Viccari

10
OMG Mengapa, hanya tidak mengembalikan NULL, 0dan NULLdua hal besar yang berbeda
deFreitas

84

Solusi lain:

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

27

Saya pikir, itu berlebihan. rs.getObject("ID_PARENT")harus mengembalikan Integerobjek atau null, jika nilai kolom sebenarnya NULL. Jadi bahkan mungkin untuk melakukan sesuatu seperti:

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
Hm, setidaknya dalam kasus saya, masalah dengan hal ini adalah bahwa panggilan getObjecttidak selalu menghasilkan Integer, karena sifat tipe kolom dalam oracle db yang saya gunakan ("Number").
Matt Mc

Masalah yang sama dengan Matt ... Dengan MySQL dan Types.BIGINT(yang harus dipetakan ke a Long) getObject()metode mengembalikan 0 bukannya nol.
xonya

2
Bisa juga lakukanrs.getObject("ID_PARENT", Integer.class)
Arlo

26

Periksa saja apakah bidangnya sedang nullatau tidak digunakan ResultSet#getObject(). Ganti -1dengan nilai null-case apa pun yang Anda inginkan.

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

Atau, jika Anda bisa menjamin bahwa Anda menggunakan tipe kolom DB yang tepat sehingga ResultSet#getObject()benar - benar mengembalikan Integer(dan dengan demikian tidak Long, Shortatau Byte), maka Anda juga bisa mengetikkannya ke Integer.

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

1
Tidak, tetapi itu akan membangun objek Integer yang tidak perlu dalam kasus non-null. (Dan BTW sebagian besar driver JDBC tidak menekan db selama panggilan metode ResultSet sama sekali ... umumnya Anda tidak mendapatkan ResultSet kembali sampai semua data datang melalui kabel).
EricS

Itu tergantung pada ukuran pengambilan. Pada sebagian besar driver, standarnya adalah 10 baris dan setelah pengambilan telah diambil, mereka akan diproses, tetapi pengambilan berikutnya tidak akan diambil sampai pemrosesan selesai.
Kristo Aun

Saya terkejut bahwa jawaban Anda bukan jawaban yang lebih baik :-) Saya memilih karena itu adalah jawaban yang tepat yang menghindari metode wasNull () yang sangat tidak aman dan sangat rumit. Bagi saya itu adalah alasan tambahan untuk berhenti menggunakan Java ;-) dan terus menggunakan VB.Net di mana RecordSet telah memecahkan masalah mudah ini sejak lebih dari 10 tahun!
schlebe

11

AFAIK cukup Anda gunakan

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

bahkan jika itu NULL.


5

Hanya pembaruan dengan Java Generics.

Anda bisa membuat metode utilitas untuk mengambil nilai opsional dari tipe Java apa pun dari ResultSet yang diberikan, yang sebelumnya dibuat.

Sayangnya, getObject (columnName, Class) tidak menghasilkan null, tetapi nilai default untuk tipe Java yang diberikan, sehingga diperlukan 2 panggilan

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;
}

Dalam contoh ini, kode Anda dapat terlihat seperti di bawah ini:

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

Senang mendapatkan umpan balik


2

Anda dapat memanggil metode ini menggunakan resultSet dan nama kolom yang memiliki tipe angka. Ini akan mengembalikan nilai Integer, atau null. Tidak akan ada nol yang dikembalikan untuk nilai kosong di database

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

Bisakah Anda masuk ke detail lebih lanjut tentang bagaimana ini memecahkan pertanyaan?
Sterling Archer

Anda dapat memanggil metode ini menggunakan resultSet dan nama kolom yang memiliki tipe angka. Ini akan mengembalikan nilai Integer, atau null. Tidak akan ada nol yang dikembalikan untuk nilai kosong di database.
amine kriaa

Luar biasa! Edit itu ke dalam jawaban Anda (dan hapus komentar setelah edit) dan Anda mendapatkan jawaban yang bagus :)
Sterling Archer

1

Dengan java 8 Anda dapat melakukan ini:

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

Dalam hal ini Anda memastikan bahwa nVal akan menjadi nol (dan bukan nol) jika nilai SQL NULL


2
tetapi tidak berlaku untukresultSet.getInt("col_name")
rapt

1
Dengan sumber data MSSQL, ini sepertinya tidak berhasil. Perlu memiliki pemeriksaan tambahanif (rs.wasNull())
alltej

1

Untuk kenyamanan, Anda bisa membuat kelas pembungkus di sekitar ResultSet yang mengembalikan nilai nol ketika ResultSetbiasanya tidak.

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

Cara pemeriksaan lain yang bagus, jika Anda telah mengontrol SQL, adalah dengan menambahkan nilai default dalam kueri itu sendiri untuk kolom int Anda. Maka cukup periksa nilai itu.

misalnya untuk database Oracle, gunakan NVL

SELECT NVL(ID_PARENT, -999) FROM TABLE_NAME;

lalu periksa

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

Tentu saja ini juga dengan asumsi bahwa ada nilai yang biasanya tidak ditemukan di kolom.


12
Saya menolak jawaban ini karena sangat mungkin menyebabkan masalah bagi banyak orang. Kolom int jika didefinisikan sebagai nullable memiliki seperangkat nilai yang terdiri dari angka positif, nol, angka negatif, dan NULL. Kapan saja seseorang dapat dengan mudah memasukkan deretan data yang valid yang berisi angka ajaib ini dan semua hal yang tiba-tiba akan memburuk. Ini pada dasarnya penerapan angka ajaib anti-pola. Jangan lakukan ini.
Matthias Hryniszak
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.