เปรียบเทียบสองอ็อบเจ็กต์ใน Java ด้วยค่า Null ที่เป็นไปได้


189

ฉันต้องการที่จะเปรียบเทียบสองสายเพื่อความเท่าเทียมกันใน Java เมื่อหนึ่งหรือทั้งสองอาจจะเป็นดังนั้นฉันไม่สามารถเพียงแค่โทรnull .equals()วิธีที่ดีที่สุดคืออะไร?

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

แก้ไข:

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

คำตอบ:


173

นี่คือสิ่งที่รหัสภายใน Java ใช้ (ในcompareวิธีการอื่น):

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

3
ทำไมไม่เพียงแค่เปลี่ยนประเภทของสตริงให้เป็นวัตถุซึ่งทำให้เป็นแบบทั่วไปมากขึ้น และมันก็เหมือนกับสิ่งที่คุณจะได้รับถ้าคุณย้ายไปที่ Java 7
Tom

3
คลาส Java ใดมีวิธีการที่คุณให้ไว้?
Volodymyr Levytskyi

30
เฮ้! คุณไม่ควรมีวิธีการเปรียบเทียบที่คืนค่าเป็นจริง / เท็จ เท่ากับไม่เหมือนกับการเปรียบเทียบ การเปรียบเทียบควรมีประโยชน์สำหรับการเรียงลำดับ คุณควรกลับ<0, ==0หรือ>0เพื่อแสดงให้เห็นเป็นที่หนึ่งที่ต่ำ / ขูดกว่าที่อื่น ๆ
Coya

10
ฉันขอแนะนำให้ใช้Objects.equals(Object, Object)เป็น Mark Rotteveel ได้ชี้ให้เห็นในคำตอบของเขา (โปรด upvote มัน)
Neuron

1
@ อีริคที่ไม่ได้ตอบคำถามที่ดีจริงๆ ฉันแน่ใจว่าคุณจะไม่เถียงคำตอบที่ดีที่สุดเสมอหนึ่งที่มีรหัสเท่านั้นซึ่งเข้ากันได้กับทุกรุ่นจาวาที่มีอยู่เสมอ
Neuron

317

ตั้งแต่ Java 7 คุณสามารถใช้วิธีการแบบคงที่จะดำเนินการตรวจสอบเท่ากับสองวัตถุโดยไม่ต้องดูแลเกี่ยวกับพวกเขาเป็นjava.util.Objects.equals(Object, Object)null

ถ้าวัตถุทั้งสองnullก็จะกลับtrueหากมีและอีกไม่ได้จะกลับมาnull falseมิฉะนั้นจะส่งคืนผลลัพธ์ของการเรียกใช้equalsบนออบเจ็กต์แรกโดยที่สองเป็นอาร์กิวเมนต์


วิธีการนี้จะยกเลิกการตรวจสอบประเภทจนกว่าจะรันไทม์ของโปรแกรม ผลที่ตามมาสองประการ: จะช้าลงในขณะใช้งานจริงและ IDE จะไม่แจ้งให้คุณทราบหากคุณพยายามเปรียบเทียบประเภทต่างๆ
averasko

10
@averasko เมื่อคุณใช้Object.equals(Object)ไม่มีการตรวจสอบประเภทเวลาคอมไพล์ Objects.equals(Object, Object)ทำงานเป็นอย่างมากเช่นเดียวกับปกติequalsและอีกอนุมาน / การตรวจสอบโดย IDE กฎเหล่านั้นมีการวิเคราะห์พฤติกรรมที่ยังได้รับการสนับสนุนสำหรับObjects.equals(Object, Object)(เช่นความคิด IntelliJ 2,016.2 มีการตรวจสอบเหมือนกันสำหรับทั้งสองเท่ากับปกติและหนึ่งจากวัตถุ)
Mark Rotteveel

2
ฉันชอบวิธีนี้ วันนี้ไม่จำเป็นต้องรวม ApacheCommons ไลบรารี่
Torsten Ojaperv

1
@SimonBaars นี่ไม่ได้ใช้งานฟังก์ชั่นบนวัตถุ null นี่เป็นวิธีการคงที่ที่คุณผ่านสองข้อโต้แย้งซึ่งอาจเป็นโมฆะหรือการอ้างอิงไปยังวัตถุ
Mark Rotteveel

8
imho สิ่งนี้ควรเป็นคำตอบที่ยอมรับได้ ฉันไม่ต้องการบูรณาการล้อในแอปพลิเคชันทุกครั้งที่ฉันเขียน
Neuron

45

สำหรับกรณีเหล่านี้จะเป็นการดีกว่าถ้าใช้Apache Commons StringUtils # เท่ากับแล้วจะจัดการกับสตริงที่ว่าง ตัวอย่างโค้ด:

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

หากคุณไม่ต้องการเพิ่มห้องสมุดเพียงแค่คัดลอกซอร์สโค้ดของStringUtils#equalsเมธอดและนำไปใช้เมื่อคุณต้องการ


29

สำหรับผู้ที่ใช้ Android ที่ไม่สามารถใช้ Objects.equals API (str1, str2) ของ API 19 ได้มีสิ่งนี้:

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

มันปลอดภัยแล้ว มันไม่ค่อยมีการใช้วิธีการ string.equals () ที่มีราคาแพงกว่าเพราะสตริงที่เหมือนกันบน Android มักจะเปรียบเทียบจริงกับตัวถูกดำเนินการ "==" ขอบคุณใช้ String Pooling ของ Androidและการตรวจสอบความยาวเป็นวิธีที่รวดเร็วในการกรองความไม่ตรงกันส่วนใหญ่

รหัสแหล่งที่มา:

/**
 * 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

ตั้งแต่เวอร์ชัน 3.5 Apache Commons StringUtils มีวิธีการดังต่อไปนี้:

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)

สิ่งเหล่านี้ให้การเปรียบเทียบสตริงที่ปลอดภัย null


6

ใช้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

เปรียบเทียบสองสตริงโดยใช้เท่ากับ (-, -) และเท่ากับ equalsIgnoreCase (-, -) ของ Apache Commons StringUtils class

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


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

นี่คือสิ่งที่คุณต้องการหรือไม่


5
กรณีนี้จะส่งคืนfalseหากทั้งสอง Strings นั้นnullอาจไม่ได้ผลลัพธ์ที่ต้องการ
JScoobyCed



0

ตกลงดังนั้น "ทางออกที่ดีที่สุดที่เป็นไปได้" หมายความว่าอย่างไร

หากคุณหมายถึงการอ่านมากที่สุดแล้วทางออกที่เป็นไปได้ทั้งหมดจะเทียบเท่ากับโปรแกรมเมอร์ Java ที่มีประสบการณ์ แต่ IMO ที่อ่านได้มากที่สุดก็คือ

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

กล่าวอีกนัยหนึ่งซ่อนการใช้งานภายในวิธีการง่ายๆที่ (ในอุดมคติ) สามารถ inline

(นอกจากนี้คุณยังสามารถ "out-source" ไปยังไลบรารียูทิลิตี้ของบุคคลที่สาม ... หากคุณใช้มันใน codebase แล้ว)


หากคุณหมายถึงนักแสดงส่วนใหญ่แล้ว:

  1. ทางออกที่มีประสิทธิภาพมากที่สุดขึ้นอยู่กับแพลตฟอร์มและบริบท
  2. หนึ่งในปัญหา "บริบท" คือความถี่สัมพัทธ์ (ไดนามิก) ของการเกิดขึ้น nullข้อโต้แย้ง
  3. มันอาจจะไม่สำคัญว่าที่รุ่นได้เร็วขึ้น ... เพราะความแตกต่างอาจจะมีขนาดเล็กเกินไปที่จะสร้างความแตกต่างให้กับประสิทธิภาพของโปรแกรมโดยรวมและ
  4. หากมันเป็นสิ่งสำคัญวิธีเดียวที่จะคิดออกว่าแพลตฟอร์มของคุณเร็วที่สุดคือลองทั้งสองเวอร์ชันและวัดความแตกต่าง
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.