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

ian_scho
sumber
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)

Richard
sumber
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;
    }
}
Patrice IMBERT
sumber
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
  }      
}
Andreas Dolk
sumber
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");
BalusC
sumber
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.

Peter Tillemans
sumber
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

luchoct
sumber
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;
    }
}
amine kriaa
sumber
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

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

    // ...

}
Jacob Crofts
sumber
-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.

Chris
sumber
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