Java null kiểm tra tại sao sử dụng == thay vì .equals ()


125

Trong Java tôi được thông báo rằng khi thực hiện kiểm tra null, người ta nên sử dụng == thay vì .equals (). những lý do cho việc này là gì?


12
Cách dễ nhất là thử kiểm tra null equals()và xem. Khi bạn thử nó sẽ ngay lập tức trở nên rõ ràng
Goran Jovic

Nhân tiện, một tìm kiếm google với từ khóa "java null check" (không có dấu ngoặc kép) đã cho tôi là một trong những bài viết hàng đầu đánh vào chủ đề này , có cùng thông tin như câu trả lời ở đây.
Mitch Schwartz

Câu trả lời:


179

Chúng là hai thứ hoàn toàn khác nhau. ==so sánh tham chiếu đối tượng, nếu có, được chứa bởi một biến. .equals()kiểm tra xem hai đối tượng có bằng nhau theo hợp đồng của họ không có nghĩa là bình đẳng. Hoàn toàn có thể cho hai trường hợp đối tượng riêng biệt là "bằng nhau" theo hợp đồng của họ. Và sau đó có một chi tiết nhỏ rằng đó equalslà một phương pháp, nếu bạn cố gắng gọi nó trên một nulltham chiếu, bạn sẽ nhận được một NullPointerException.

Ví dụ:

class Foo {
    private int data;

    Foo(int d) {
        this.data = d;
    }

    @Override
    public boolean equals(Object other) {
        if (other == null || other.getClass() != this.getClass()) {
           return false;
        }
        return ((Foo)other).data == this.data;
    }

    /* In a real class, you'd override `hashCode` here as well */
}

Foo f1 = new Foo(5);
Foo f2 = new Foo(5);
System.out.println(f1 == f2);
// outputs false, they're distinct object instances

System.out.println(f1.equals(f2));
// outputs true, they're "equal" according to their definition

Foo f3 = null;
System.out.println(f3 == null);
// outputs true, `f3` doesn't have any object reference assigned to it

System.out.println(f3.equals(null));
// Throws a NullPointerException, you can't dereference `f3`, it doesn't refer to anything

System.out.println(f1.equals(f3));
// Outputs false, since `f1` is a valid instance but `f3` is null,
// so one of the first checks inside the `Foo#equals` method will
// disallow the equality because it sees that `other` == null

ý bạn là public int datasao
Jé Queue

@Xepoch: Không, tôi thường không tạo các trường công khai (mặc dù điều này thực sự không quan trọng đối với ví dụ này). Tại sao?
TJ Crowder

@TJ Crowder "Chúng là hai thứ hoàn toàn khác nhau .." nói chung là có. Tuy nhiên, việc thực hiện mặc định của cả hai là như nhau, nếu sự hiểu biết của tôi là chính xác. Nhìn vào mã nguồn, .equals () về cơ bản thực hiện kiểm tra ==. hg.openjdk.java.net/jdk7/jdk7/jdk/file/tip/src/share/ classes / Lỗi
Ayush

1
@Ayush - Đó là mặc định trong Object, vâng. Mặc dù vậy, nó bị ghi đè bởi một số lượng lớn các lớp JDK. Nhưng vấn đề không phải là về việc thực hiện, đó là về ngữ nghĩa. (Lưu ý bên lề: JDK7 đã hết hạn.)
TJ Crowder

Phải, điều đó có ý nghĩa, chỉ muốn làm rõ.
Ayush

38

nếu bạn gọi .equals()trên nullbạn sẽ nhận đượcNullPointerException

Vì vậy, luôn luôn nên kiểm tra tính vô hiệu trước khi gọi phương thức khi áp dụng

if(str!=null && str.equals("hi")){
 //str contains hi
}  

Cũng thấy


34
Ví dụ của bạn thường được viết tốt hơn như if ("hi".equals(str)).
ColinD

3
@ user368186: điểm không phải là liệu phương thức bằng có bao gồm kiểm tra null hay không. Nếu tham chiếu đối tượng của bạn là null, thì cuộc gọi someObject.equals(null)sẽ tăng lên NullPointerExceptionmà không bao giờ nhập phương thức bằng.
Dave Costa

2
@ColinD Đồng ý chỉ trình diễn ở đây
Jigar Joshi

2
Luôn luôn nên tránh null bằng mọi giá, vì vậy bạn không cần kiểm tra null;).
fwielstra

2
Bạn luôn có thể sử dụng Objects.equals(a, b)Nó sẽ không tăng NullPulumException, nhưng nó vẫn phụ thuộc vào phương thức "bằng" của "a" và "b"
Dominik Minc

29

Ngoài câu trả lời được chấp nhận ( https://stackoverflow.com/a/4501084/6276704 ):

Vì Java 1.7, nếu bạn muốn so sánh hai Đối tượng có thể là null, tôi khuyên bạn nên sử dụng hàm này:

Objects.equals(onePossibleNull, twoPossibleNull)

java.util.Objects

Lớp này bao gồm các phương thức tiện ích tĩnh để vận hành trên các đối tượng. Các tiện ích này bao gồm các phương thức không an toàn hoặc không khoan nhượng để tính toán mã băm của một đối tượng, trả về một chuỗi cho một đối tượng và so sánh hai đối tượng.

Từ: 1.7


2
Chỉ để làm cho người khác thấy rõ hơn (xem câu trả lời của chin90 hoặc JavaDoc ): Objects.equals(null, null)sẽ trở lại true- hãy ghi nhớ điều đó.
Thomas

20

Trong Java 0 hoặc null là các loại đơn giản và không phải là đối tượng.

Phương thức equals () không được xây dựng cho các loại đơn giản. Các loại đơn giản có thể được khớp với ==.


4
upvote cho câu trả lời thực sự hữu ích nhất trái ngược với câu trả lời rõ ràng "NullPulumException sẽ được trả lại".
Volk

4
foo.equals(null)

Điều gì xảy ra nếu foo là null?

Bạn nhận được một NullPulumException.


3

Nếu một biến Object là null, người ta không thể gọi một phương thức equals () theo nó, do đó kiểm tra tham chiếu đối tượng của null là đúng.


2

Nếu bạn thử gọi bằng với tham chiếu đối tượng null, thì bạn sẽ bị ném ngoại lệ con trỏ null.


2

Theo các nguồn , không có vấn đề gì khi sử dụng để thực hiện phương thức mặc định:

public boolean equals(Object object) {
    return this == object;
}

Nhưng bạn không thể chắc chắn về equalslớp học tùy chỉnh.


Nó quan trọng, vì equalschỉ có thể trả về falsehoặc gây ra một NullPointerException(hoặc một cái gì đó khác nếu equalsphương pháp overriden là vô nghĩa).
Tom

2

Nếu chúng ta sử dụng phương thức => .equals

if(obj.equals(null))  

// Which mean null.equals(null) when obj will be null.

Khi obj của bạn là null, nó sẽ ném Null Point Exception.

vì vậy chúng ta nên sử dụng ==

if(obj == null)

nó sẽ so sánh các tài liệu tham khảo.


2

Object.equals là null an toàn, tuy nhiên, hãy lưu ý rằng nếu hai đối tượng là null, object.equals sẽ trả về true, vì vậy hãy chắc chắn kiểm tra xem các đối tượng bạn đang so sánh không null (hoặc giữ giá trị null) trước khi sử dụng object.equals cho so sánh.

String firstname = null;
String lastname = null;

if(Objects.equals(firstname, lastname)){
    System.out.println("equal!");
} else {
    System.out.println("not equal!");
}

Đoạn trích trên sẽ trả về bằng nhau!


Như JavaDoc đã nêu (luôn luôn khôn ngoan khi đọc chúng): Consequently, if both arguments are null, true is returned. ...:)
Thomas

1

Vì bằng là một hàm xuất phát từ lớp Object, nên hàm này so sánh các mục của lớp. nếu bạn sử dụng nó với null thì nó sẽ trả về sai vì nguyên nhân nội dung lớp không phải là null. Ngoài ra == so sánh tham chiếu đến một đối tượng.


Chà, kết quả chỉ có thể falsehoặc NullPointerException(nếu equalskhông được ghi đè lên một cái gì đó xấu).
Tom

1

đây là một ví dụ str != nullnhưng str.equals(null)khi sử dụngorg.json

 JSONObject jsonObj = new JSONObject("{field :null}");
 Object field = jsonObj.get("field");
 System.out.println(field != null);        // => true
 System.out.println( field.equals(null)); //=> true
 System.out.println( field.getClass());  // => org.json.JSONObject$Null




EDIT: đây là lớp org.json.JSONObject $ Null :

/**
 * JSONObject.NULL is equivalent to the value that JavaScript calls null,
 * whilst Java's null is equivalent to the value that JavaScript calls
 * undefined.
 */
private static final class Null {

    /**
     * A Null object is equal to the null value and to itself.
     *
     * @param object
     *            An object to test for nullness.
     * @return true if the object parameter is the JSONObject.NULL object or
     *         null.
     */
    @Override
    public boolean equals(Object object) {
        return object == null || object == this;
    }  
}

Vấn đề ở đây là field.equals(null)trả về đúng sự thật. Điều này phá vỡ hành vi Java thông thường và do đó gây nhầm lẫn. Nó chỉ nên làm việc cho field.equals("null"), ít nhất là theo quan điểm của tôi. Tôi không biết tại sao các nhà phát triển thư viện nghĩ rằng điều này sẽ tốt để hỗ trợ.
Tom

Btw, câu đầu tiên của bạn có vấn đề về ngữ pháp và không rõ ý của bạn với nó. Bạn có nghĩa là "Đây là một ví dụ nơi str != nullstr.equals(null)trở lại truekhi sử dụng org.json ."?
Tom

Tôi nghĩ đó là bởi vì khóa jsonObjectchứa "trường" đó là lý do tại sao fieldkhông phải là null, nó có một tham chiếu chứa json.org.JSONObject$Null đối tượng
dina

Có, nhưng tôi sẽ không Nullthích nullvà sẽ sử dụng "null"thay thế. Nhưng tôi đoán họ đã làm điều đó để tránh yêu cầu String. Nhưng ngay cả với lib đó, field.equals(null)vẫn là gần như luôn luôn là một vấn đề: P.
Tom

0

Vì vậy, tôi không bao giờ bị nhầm lẫn và tránh các vấn đề với giải pháp này:

if(str.trim().length() <=0 ) {
   // is null !
}

5
Nếu str là null thì đây sẽ là một NPE
typoerrpr

Ngoài ra, một chuỗi rỗng ( ""có độ dài 0) là một cái gì đó hoàn toàn khác với một nulltham chiếu (tức là không có chuỗi).
Thomas

0

Tôi đã gặp trường hợp này đêm qua.
Tôi xác định rằng đơn giản là:

Không tồn tại phương thức equals () cho null
Vì vậy, bạn không thể gọi một phương thức không tồn tại nếu bạn không có
- >>> Đó là lý do tại sao chúng tôi sử dụng == để kiểm tra null


0

Mã của bạn vi phạm luật của Demeter. Đó là lý do tại sao nó tốt hơn để cấu trúc lại thiết kế. Như một giải pháp thay thế, bạn có thể sử dụng Tùy chọn

   obj = Optional.ofNullable(object1)
    .map(o -> o.getIdObject11())
    .map(o -> o.getIdObject111())
    .map(o -> o.getDescription())
    .orElse("")

ở trên là để kiểm tra phân cấp của một đối tượng để chỉ cần sử dụng

Optional.ofNullable(object1) 

nếu bạn chỉ có một đối tượng để kiểm tra

Hi vọng điêu nay co ich !!!!


-3

Bạn luôn có thể làm

if (str == null || str.equals(null))

Điều này trước tiên sẽ kiểm tra tham chiếu đối tượng và sau đó kiểm tra chính đối tượng cung cấp tham chiếu không null.


if (str == null | | str.equals (null) || str.equals (""))
Lou Morda

tôi đã sử dụng câu trả lời của bạn và thêm một kiểm tra cho một chuỗi trống! nếu tôi không nhầm, null và "" không giống nhau.
Lou Morda

4
Có phải nó không hoàn toàn dư thừa để thêm kiểm tra thứ 2 cho null?
Justin Rowe

2
@JustinRowe Nó không chỉ dư thừa mà còn rất sai. Xin vui lòng, không bao giờ làm một cái gì đó như x.equals(null).
Tom

@Tom, JustinRowe vui lòng xem câu trả lời của tôi ở trên tại sao điều này không dư thừa cũng không hoàn thành stackoverflow.com/questions/4501061/ chủ
dina
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.