Java ResultSetからのnull int値の確認


277

Javaでは、列がプリミティブなint型にキャストされているResultSetからnull値をテストしようとしています。

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

上記のコードの断片から、これを行うためのより良い方法はありますか、そして2番目のwasNull()テストは冗長であると思いますか?

私たちを教育し、ありがとう


13
データベースにnull許容列があり、JavaではIntegerで表されるため、この質問が見つかりました。データベースにnull許容の数値列があることは、ResultSet APIが少しエレガントに対応するのに十分一般的であると考えるでしょう。
spaaarky21 2012年

これは正接であり、普遍的ではないため、これを回答として投稿していません。これに対する私の通常の解決策IF(colName = NULL, 0, colName) AS colNameは、SELECTステートメント(できればストアドプロシージャ)に入れることです。哲学的には、これは、DBがアプリに準拠する必要があるか、またはその逆であるかによって決まります。SQLはNULLを簡単に処理し、多くのSQLコンシューマーは処理しないため(つまりjava.sql.ResultSet)、可能な場合はDBで処理することを選択します。(もちろん、これは概念的にNULLと0があなたの目的にとって同等であることを前提としています。)
s.co.tt '30 / 10/30

回答:


368

ResultSet.getIntフィールド値がの場合のデフォルトNULLはreturnです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-ResultSetのgetIntのjavadocを参照してください:「戻り値:列の値。値がSQL NULLの場合、返される値は0です」
Cowan

150
真実は、確かに、ばかげています。getInt()なければならないgetInteger()返すIntegerであるnullDBの値である場合null。開発者は本当にこれを台無しにしました。
ryvantage 2014年

7
このロジックに従って@sactiwを実行すると、NPEを回避するためにJavaのすべてが開発されているはずですが、そうではありません。NPEは、言語の内部APIではなく、アプリ開発者の責任です。
マテウスヴィッカリ2016年

10
OMGなぜそうなったのか、単にNULLを返さないの0NULL、2つの大きな違いがある
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オブジェクトまたはを返します。したがって、次のようなこともできるはずです。nullNULL

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使用しているoracle dbの列タイプの性質( "Number")のため、呼び出しが必ずしも整数を返さないことです。
Matt Mc

Mattの同じ問題... MySQLとTypes.BIGINT(それをにマップする必要がありますLonggetObject()メソッドはnullではなく0を返します。
xonya

2
またできますrs.getObject("ID_PARENT", Integer.class)
Arlo

26

フィールドがnullを使用しているかどうかを確認してくださいResultSet#getObject()。代替-1好きなヌルの場合の値を持ちます。

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

または、正しいDB列型を使用して、ResultSet#getObject()本当にを返すことが保証されている場合Integer(したがってLongShortまたはを返さない場合Byte)、それをに型キャストすることもできますInteger

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

1
いいえ。ただし、null以外の場合は不要なIntegerオブジェクトが作成されます。(そして、BTWのほとんどのJDBCドライバーは、ResultSetメソッドの呼び出し中にデータベースにヒットしません。
EricS 2012年

フェッチサイズに依存します。ほとんどのドライバーでは、デフォルトは10行で、フェッチが取得されるとそれらは処理されますが、次のフェッチは処理が完了するまで取得されません。
クリストアウン2013

私はあなたの答えがより良い答えではないことに驚いています:-)非常にトリッキーで安全でないwasNull()メソッドを回避する正しい答えなので、私は投票します。私にとっては、Javaの使用をやめ、VB.Netを使い続けるのは補足的な理由です。10年以上の間、RecordSetがこの簡単な問題を解決してきました。
schlebe 2018


5

Java Genericsの更新のみ。

以前にキャストされた特定のResultSetから任意のJavaタイプのオプションの値を取得するユーティリティメソッドを作成できます。

残念ながら、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およびNumberタイプの列名を使用して呼び出すことができます。Integer値またはnullを返します。データベース内の空の値に対してゼロは返されません

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タイプの列名を使用して呼び出すことができます。Integer値またはnullを返します。データベース内の空の値に対してゼロが返されることはありません。
アミンクリア

優れた!それをあなたの答えに編集してください(そして編集後のコメントを削除してください)そしてあなたはあなた自身に良い答えを持っています:)
Sterling Archer

1

Java 8でこれを行うことができます:

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

その場合、SQL値がNULLの場合、nValがnull(ゼロではない)になることを確認します。


2
には適用されませんresultSet.getInt("col_name")
猛烈に'19

1
MSSQLデータソースでは、これは機能していないようです。次の追加チェックが必要ですif (rs.wasNull())
alltej 2018年

1

便宜上、ResultSet通常はnull値を返さないnull値を返す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
多くの人に問題を引き起こす可能性が非常に高いので、私はこの回答に反対票を投じました。null可能として定義されている場合、int列には、正の数、ゼロ、負の数、およびNULLで構成される値のセットがあります。いつでも、このマジックナンバーを含む有効なデータ行を挿入するだけで、突然の事態はすべてうまくいきません。それは基本的にマジックナンバーアンチパターンの実装です。これを行わないでください。
Matthias Hryniszak 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.