So sánh hai đối tượng trong Java với các giá trị null có thể


189

Tôi muốn so sánh hai chuỗi cho sự bình đẳng trong Java, khi một hoặc cả hai có thể null, vì vậy tôi không thể gọi một cách đơn giản .equals(). cách tốt nhất là gì?

boolean compare(String str1, String str2) {
    ...
}

Biên tập:

return ((str1 == str2) || (str1 != null && str1.equals(str2)));

Câu trả lời:


173

Đây là những gì mã nội bộ Java sử dụng (trên các comparephương thức khác ):

public static boolean compare(String str1, String str2) {
    return (str1 == null ? str2 == null : str1.equals(str2));
}

3
Tại sao không chỉ thay đổi các loại Chuỗi thành Đối tượng - làm cho nó chung chung hơn? Và sau đó, nó giống như những gì bạn sẽ nhận được nếu bạn chuyển sang Java 7.
Tom

3
Lớp java nào chứa phương thức bạn cung cấp?
Volodymyr Levytskyi

30
Chào! bạn không nên có một phương thức so sánh trả về true / false. Bằng không giống như so sánh. So sánh sẽ hữu ích cho việc sắp xếp. Bạn nên trả lại <0, ==0hoặc >0để chỉ ra cái nào là thấp / vắt tay hơn người kia
Coya

10
tôi đề nghị sử dụng Objects.equals(Object, Object)như Mark Rotteveel đã chỉ ra trong câu trả lời của anh ấy (vui lòng nâng cấp nó)
Neuron

1
@Eric không thực sự làm cho nó ít câu trả lời hay. Tôi chắc chắn rằng bạn sẽ không tranh luận câu trả lời hay nhất luôn là câu trả lời chỉ chứa mã tương thích với mọi phiên bản java luôn tồn tại
Neuron

315

Vì Java 7, bạn có thể sử dụng phương thức tĩnh java.util.Objects.equals(Object, Object)để thực hiện kiểm tra bằng nhau trên hai đối tượng mà không cần quan tâm đến chúng null.

Nếu cả hai đối tượng là nullnó sẽ trở lại true, nếu một nullvà một đối tượng khác sẽ không trở lại false. Nếu không, nó sẽ trả về kết quả của việc gọi equalsđối tượng đầu tiên với đối số thứ hai là đối số.


Cách tiếp cận này trì hoãn việc kiểm tra kiểu cho đến khi thời gian chạy của chương trình. hai hậu quả: nó sẽ chậm hơn trong thời gian chạy và IDE sẽ không cho bạn biết nếu bạn vô tình thử so sánh các loại khác nhau.
averasko

10
@averasko Khi bạn sử dụng Object.equals(Object), không có kiểm tra loại thời gian biên dịch. Các Objects.equals(Object, Object)công việc rất giống với bình thường equalsvà suy luận / kiểm tra bởi IDE, các quy tắc đó là các heuristic cũng được hỗ trợ cho Objects.equals(Object, Object)(ví dụ IntelliJ IDEA 2016.2 có cùng một kiểm tra cho cả hai bình thường và một từ đối tượng).
Mark Rotteveel

2
Tôi thích cách tiếp cận này. Không cần bao gồm một số thư viện ApacheCommons cho những thứ hiện nay.
Torsten Ojaperv

1
@SimonBaars Đây không phải là chạy một hàm trên một đối tượng null, đây là một phương thức tĩnh mà bạn truyền hai đối số, có thể là null hoặc tham chiếu đến một đối tượng.
Đánh dấu Rotteveel

8
Imho đây sẽ là câu trả lời được chấp nhận. Tôi không muốn phát minh lại bánh xe trong mỗi ứng dụng tôi viết
Neuron

45

Đối với những trường hợp này, tốt hơn là sử dụng Apache Commons StringUtils # bằng , nó đã xử lý các chuỗi null. Mẫu mã:

public boolean compare(String s1, String s2) {
    return StringUtils.equals(s1, s2);
}

Nếu bạn không muốn thêm thư viện, chỉ cần sao chép mã nguồn của StringUtils#equalsphương thức và áp dụng nó khi bạn cần.


28

Đối với những người dùng trên Android, những người không thể sử dụng Object.equals của API 19 (str1, str2), có:

android.text.TextUtils.equals(str1, str2);

Nó là null an toàn. Nó hiếm khi phải sử dụng phương thức string.equals () đắt tiền hơn vì các chuỗi giống hệt nhau trên Android hầu như luôn so sánh đúng với toán hạng "==" nhờ vào Chuỗi tổng hợp của Android và kiểm tra độ dài là cách nhanh chóng để lọc ra hầu hết các điểm không phù hợp.

Mã nguồn:

/**
 * Returns true if a and b are equal, including if they are both null.
 * <p><i>Note: In platform versions 1.1 and earlier, this method only worked  well if
 * both the arguments were instances of String.</i></p>
 * @param a first CharSequence to check
 * @param b second CharSequence to check
 * @return true if a and b are equal
 */
public static boolean equals(CharSequence a, CharSequence b) {
    if (a == b) return true;
    int length;
    if (a != null && b != null && (length = a.length()) == b.length()) {
        if (a instanceof String && b instanceof String) {
            return a.equals(b);
        } else {
            for (int i = 0; i < length; i++) {
                if (a.charAt(i) != b.charAt(i)) return false;
            }
            return true;
        }
    }
    return false;
}

7

Do phiên bản 3.5 Apache Commons StringUtils có các phương thức sau:

static int  compare(String str1, String str2)
static int  compare(String str1, String str2, boolean nullIsLess)
static int  compareIgnoreCase(String str1, String str2)
static int  compareIgnoreCase(String str1, String str2, boolean nullIsLess)

Chúng cung cấp so sánh chuỗi an toàn null.


6

Sử dụng Java 8:

private static Comparator<String> nullSafeStringComparator = Comparator
        .nullsFirst(String::compareToIgnoreCase); 

private static Comparator<Metadata> metadataComparator = Comparator
        .comparing(Metadata::getName, nullSafeStringComparator)
        .thenComparing(Metadata::getValue, nullSafeStringComparator);

public int compareTo(Metadata that) {
    return metadataComparator.compare(this, that);
}

4

So sánh hai chuỗi bằng cách sử dụng phương thức equals (-, -) và equalsIgnoreCase (-, -) của lớp Apache Commons StringUtils.

StringUtils.equals (-, -) :

StringUtils.equals(null, null)   = true
StringUtils.equals(null, "abc")  = false
StringUtils.equals("abc", null)  = false
StringUtils.equals("abc", "abc") = true
StringUtils.equals("abc", "ABC") = false

StringUtils.equalsIgnoreCase (-, -) :

StringUtils.equalsIgnoreCase(null, null)   = true
StringUtils.equalsIgnoreCase(null, "abc")  = false
StringUtils.equalsIgnoreCase("xyz", null)  = false
StringUtils.equalsIgnoreCase("xyz", "xyz") = true
StringUtils.equalsIgnoreCase("xyz", "XYZ") = true

3

Bạn có thể sử dụng java.util.Objectsnhư sau.

public static boolean compare(String str1, String str2) {
    return Objects.equals(str1, str2);
}

2
boolean compare(String str1, String str2) {
    if(str1==null || str2==null) {
        //return false; if you assume null not equal to null
        return str1==str2;
    }
    return str1.equals(str2);
}

đây có phải là những gì bạn mong muốn?


5
Trường hợp này trả về falsenếu cả hai Chuỗi nullcó thể không phải là kết quả mong muốn.
JScoobyCed

1
boolean compare(String str1, String str2) {
    if (str1 == null || str2 == null)
        return str1 == str2;

    return str1.equals(str2);
}

1
boolean compare(String str1, String str2) {
  return (str1==null || str2==null) ? str1 == str2 : str1.equals(str2);
}

0

OK, vậy "giải pháp tốt nhất có thể" nghĩa là gì?

Nếu bạn có nghĩa là dễ đọc nhất, thì tất cả các giải pháp có thể tương đương với một lập trình viên Java có kinh nghiệm. Nhưng IMO dễ đọc nhất là đây

 public boolean compareStringsOrNulls(String str1, String str2) {
     // Implement it how you like
 }

Nói cách khác, ẩn việc thực hiện bên trong một phương thức đơn giản (lý tưởng) có thể được nội tuyến.

(Bạn cũng có thể "out-source" cho thư viện tiện ích của bên thứ 3 ... nếu bạn đã sử dụng nó trong cơ sở mã của mình.)


Nếu bạn có ý nghĩa nhất là biểu diễn, thì:

  1. giải pháp hiệu quả nhất phụ thuộc vào nền tảng và bối cảnh,
  2. một trong những vấn đề "bối cảnh" là tần suất xuất hiện tương đối (động) của các nullđối số,
  3. có lẽ không quan trọng mà phiên bản là nhanh hơn ... vì sự khác biệt có lẽ là quá nhỏ để tạo sự khác biệt đến việc thực hiện ứng dụng tổng thể, và
  4. nếu có vấn đề, cách duy nhất để tìm ra cách nhanh nhất TRÊN NỀN TẢNG CỦA BẠN là thử cả hai phiên bản và đo lường sự khác biệt.
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.