Kiểm tra giá trị int null từ Bộ kết quả Java


277

Trong Java, tôi đang cố gắng kiểm tra giá trị null, từ Kết quả, trong đó cột đang được truyền sang kiểu int nguyên thủy .

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

Từ đoạn mã trên, có cách nào tốt hơn để làm điều này không, và tôi giả sử rằng thử nghiệm wasNull () thứ hai là dự phòng?

Giáo dục chúng tôi và cảm ơn


13
Tôi tìm thấy câu hỏi này bởi vì tôi có một cột không thể trong cơ sở dữ liệu và nó được đại diện bởi một Integer trong Java. Bạn sẽ nghĩ rằng việc có một cột số không có giá trị trong cơ sở dữ liệu sẽ đủ phổ biến để API Kết quả sẽ phù hợp với nó một cách thanh lịch hơn một chút.
spaaarky21

Tôi không đăng bài này dưới dạng câu trả lời vì nó tiếp tuyến và không phổ biến: Giải pháp thông thường của tôi cho vấn đề này là đưa IF(colName = NULL, 0, colName) AS colNamevào SELECTtuyên bố (tốt nhất là trong một lưu trữ được lưu trữ). Về mặt triết học, điều này phụ thuộc vào việc DB nên phù hợp với ứng dụng hay ngược lại. Vì SQL xử lý NULL dễ dàng và nhiều người tiêu dùng SQL không (nghĩa là java.sql.ResultSet), tôi chọn xử lý nó tại DB khi có thể. (Tất nhiên, điều này giả định rằng về mặt khái niệm NULL và zero là tương đương với mục đích của bạn.)
s.co.tt

Câu trả lời:


368

Giá trị mặc định ResultSet.getIntkhi giá trị trường là NULLtrả về 0, đây cũng là giá trị mặc định cho iValkhai báo của bạn . Trong trường hợp kiểm tra của bạn là hoàn toàn dư thừa.

Nếu bạn thực sự muốn làm một cái gì đó khác nếu giá trị trường là NULL, tôi đề nghị:

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

(Được chỉnh sửa dưới dạng @martin nhận xét bên dưới; mã OP như được viết sẽ không được biên dịch vì iValkhông được khởi tạo)


2
Tôi vừa tìm thấy tuyên bố tương tự trong các tài liệu. Nó có giá trị một chủ đề riêng biệt trên SO imho. ( java.sun.com/j2se/1.4.2/docs/api/java/sql/, )
Roman

6
@Roman - xem javadoc cho getInt trong Kết quả: "Trả về: giá trị cột; nếu giá trị là SQL NULL, giá trị được trả về là 0"
Cowan

150
Sự thật là, thực sự, vô lý. getInt()nên getInteger()trả về một giá trị Integerđó là nullnếu giá trị DB là null. Các nhà phát triển thực sự làm rối tung cái này lên.
ryvantage

7
@sactiw theo logic này, mọi thứ trên java nên được phát triển để tránh NPE, đây không phải là trường hợp. Tránh NPE là trách nhiệm của các nhà phát triển ứng dụng, không phải API nội bộ của ngôn ngữ.
Mateus Viccari

10
OMG Tại sao, đơn giản là không trả về NULL 0NULLlà hai điều lớn khác nhau
deFreitas

84

Giải pháp khác:

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

27

Tôi nghĩ rằng, nó là dư thừa. rs.getObject("ID_PARENT")sẽ trả về một Integerđối tượng hoặc null, nếu giá trị cột thực sự là NULL. Vì vậy, nó thậm chí có thể làm một cái gì đó như:

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
Hừm, ít nhất là trong trường hợp của tôi, vấn đề với điều này là việc gọi getObjectkhông nhất thiết phải trả về một Số nguyên, do bản chất của loại cột trong orory db tôi đang sử dụng ("Số").
Matt Mc

Vấn đề tương tự của Matt ... Với MySQL và Types.BIGINT(nên được ánh xạ tới a Long) getObject()phương thức trả về 0 thay vì null.
xonya

2
Cũng có thể làmrs.getObject("ID_PARENT", Integer.class)
Arlo

26

Chỉ cần kiểm tra xem trường đang nullsử dụng hay không ResultSet#getObject(). Thay thế -1với bất kỳ giá trị trường hợp null nào bạn muốn.

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

Hoặc, nếu bạn có thể đảm bảo rằng bạn sử dụng đúng loại cột DB để ResultSet#getObject()thực sự trả về một Integer(và do đó thì không Long, Shorthoặc Byte), thì bạn cũng có thể chỉ cần gõ nó thành một Integer.

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

1
Không, nhưng nó sẽ xây dựng một đối tượng Integer không cần thiết trong trường hợp không null. (Và hầu hết các trình điều khiển JDBC của BTW không gặp db trong bất kỳ lệnh gọi phương thức Kết quả nào cả ... nói chung, bạn không lấy lại Kết quả cho đến khi tất cả dữ liệu đi qua dây).
EricS

Nó phụ thuộc vào kích thước tìm nạp. Trong hầu hết các trình điều khiển, mặc định là 10 hàng và một khi quá trình tìm nạp đã được truy xuất, chúng sẽ được xử lý, nhưng lần tìm nạp tiếp theo sẽ không được truy xuất cho đến khi quá trình xử lý kết thúc.
Kristo Aun

Tôi ngạc nhiên rằng câu trả lời của bạn không phải là câu trả lời tốt hơn :-) Tôi bỏ phiếu vì đó là câu trả lời phù hợp để tránh phương thức wasNull () rất khó bảo mật. Đối với tôi, đó là một lý do bổ sung để ngừng sử dụng Java ;-) và tiếp tục sử dụng VB.Net, nơi RecordSet đã giải quyết vấn đề dễ dàng này từ hơn 10 năm qua!
schlebe

11

AFAIK bạn chỉ cần sử dụng

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

ngay cả khi đó là NULL.


5

Chỉ là một bản cập nhật với Java Generics.

Bạn có thể tạo một phương thức tiện ích để lấy một giá trị tùy chọn của bất kỳ loại Java nào từ một Bộ kết quả đã cho, đã được đúc trước đó.

Thật không may, getObject (cộtName, Class) không trả về null, nhưng giá trị mặc định cho loại Java đã cho, do đó bắt buộc phải có 2 cuộc gọi

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

Trong ví dụ này, mã của bạn có thể trông như dưới đây:

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

Rất vui khi nhận được phản hồi


2

Bạn có thể gọi phương thức này bằng cách sử dụng resultset và tên cột có Kiểu số. Nó sẽ trả về giá trị Integer hoặc null. Sẽ không có số không được trả về cho giá trị trống trong cơ sở dữ liệu

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

Bạn có thể vui lòng đi vào chi tiết hơn về cách giải quyết câu hỏi này không?
Sterling Archer

Bạn có thể gọi phương thức này bằng cách sử dụng resultset và tên cột có Kiểu số. Nó sẽ trả về giá trị Integer hoặc null. Sẽ không có số không được trả về cho giá trị trống trong cơ sở dữ liệu.
amin kriaa

Thông minh! Chỉnh sửa câu trả lời của bạn (và xóa nhận xét sau khi chỉnh sửa) và bạn có cho mình một câu trả lời hay :)
Sterling Archer

1

Với java 8, bạn có thể làm điều này:

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

Trong trường hợp đó, bạn đảm bảo rằng nVal sẽ là null (chứ không phải 0) nếu giá trị SQL là NULL


2
nhưng không áp dụng choresultSet.getInt("col_name")
say mê

1
Với nguồn dữ liệu MSSQL, điều này dường như không hoạt động. Nó cần phải có kiểm tra bổ sungif (rs.wasNull())
alltej

1

Để thuận tiện, bạn có thể tạo một lớp trình bao quanh Kết quả trả về giá trị null khi ResultSetthông thường sẽ không.

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

Một cách tốt khác để kiểm tra, nếu bạn có quyền kiểm soát SQL, là thêm một giá trị mặc định trong chính truy vấn cho cột int của bạn. Sau đó, chỉ cần kiểm tra giá trị đó.

ví dụ: đối với cơ sở dữ liệu Oracle, hãy sử dụng NVL

SELECT NVL(ID_PARENT, -999) FROM TABLE_NAME;

sau đó kiểm tra

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

Tất nhiên điều này cũng theo giả định rằng có một giá trị thường không được tìm thấy trong cột.


12
Tôi đã bỏ phiếu xuống câu trả lời này vì nó rất có thể gây ra vấn đề cho nhiều người. Một cột int nếu được định nghĩa là nullable có một tập hợp các giá trị bao gồm số dương, số 0, số âm và NULL. Tại bất kỳ thời điểm nào, người ta có thể chỉ cần chèn hàng dữ liệu hợp lệ có chứa số ma thuật này và tất cả những điều bất ngờ sẽ trở nên tồi tệ. Về cơ bản, đó là việc thực hiện mô hình chống ma thuật số. Đừng làm điều này.
Matthias Hryniszak
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.