Bandingkan dua objek di Jawa dengan kemungkinan nilai nol


189

Saya ingin membandingkan dua string untuk kesetaraan di Jawa, ketika salah satu atau keduanya bisa null, jadi saya tidak bisa begitu saja menelepon .equals(). Apakah cara terbaiknya?

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

Edit:

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

Jawaban:


173

Inilah yang digunakan kode internal Java (pada comparemetode lain ):

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

3
Mengapa tidak hanya mengubah tipe String ke Objek - membuatnya lebih umum? Dan kemudian itu sama dengan apa yang akan Anda dapatkan jika Anda pindah ke Jawa 7.
Tom

3
Kelas java mana yang berisi metode yang Anda berikan?
Volodymyr Levytskyi

30
Hei! Anda seharusnya tidak memiliki metode perbandingan yang mengembalikan benar / salah. Persamaan tidak sama dengan membandingkan. Bandingkan harus bermanfaat untuk menyortir. Anda harus kembali <0, ==0atau >0untuk menunjukkan mana yang lebih rendah / parutan dari yang lain
coya

10
Saya sarankan menggunakan Objects.equals(Object, Object)sebagaimana Mark Rotteveel telah tunjukkan dalam jawabannya (tolong beri dukungan)
Neuron

1
@ Eric itu tidak benar-benar membuatnya kurang dari jawaban yang bagus. Saya yakin Anda tidak akan berdebat jawaban terbaik selalu yang hanya berisi kode yang kompatibel dengan setiap versi java yang selalu ada
Neuron

318

Karena Java 7 Anda dapat menggunakan metode statis java.util.Objects.equals(Object, Object)untuk melakukan pemeriksaan yang sama pada dua objek tanpa peduli keberadaannya null.

Jika kedua objek nullitu akan kembali true, jika satu nulldan yang lain bukan akan kembali false. Kalau tidak, itu akan mengembalikan hasil memanggil equalsobjek pertama dengan yang kedua sebagai argumen.


pendekatan ini menolak pemeriksaan tipe sampai runtime program. dua konsekuensi: itu akan lebih lambat saat runtime dan IDE tidak akan memberi tahu Anda jika Anda secara tidak sengaja mencoba membandingkan berbagai jenis.
averasko

10
@averasko Ketika Anda menggunakan Object.equals(Object)tidak ada pemeriksaan jenis waktu kompilasi. The Objects.equals(Object, Object)bekerja sangat banyak yang sama seperti normal equals, dan re inferensi / pemeriksaan oleh IDE, aturan-aturan yang heuristik yang juga didukung untuk Objects.equals(Object, Object)(misalnya IntelliJ IDEA 2016,2 memiliki cek yang sama untuk kedua equals normal dan satu dari Objects).
Mark Rotteveel

2
Saya suka pendekatan ini. Tidak perlu menyertakan beberapa perpustakaan ApacheCommons untuk hal-hal hari ini.
Torsten Ojaperv

1
@SimonBaars Ini tidak menjalankan fungsi pada objek nol, ini adalah metode statis yang Anda berikan dua argumen, yang bisa nol, atau referensi ke objek.
Mark Rotteveel

8
Iho ini harus menjadi jawaban yang diterima. Saya tidak ingin menemukan kembali roda di setiap aplikasi yang saya tulis
Neuron

45

Untuk kasus-kasus ini akan lebih baik menggunakan sama dengan Apache Commons StringUtils # , itu sudah menangani string null. Contoh kode:

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

Jika Anda tidak ingin menambahkan perpustakaan, hanya menyalin kode sumber dari StringUtils#equalsmetode dan menerapkannya ketika Anda membutuhkannya.


29

Bagi mereka yang menggunakan Android, yang tidak dapat menggunakan Objects.equals API 19 (str1, str2), ada ini:

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

Ini nol aman. Jarang harus menggunakan metode string.equals () yang lebih mahal karena string identik pada android hampir selalu benar dibandingkan dengan operan "==" berkat String Pooling Android , dan pengecekan panjang adalah cara cepat untuk menyaring sebagian besar ketidakcocokan.

Kode sumber:

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

Sejak versi 3.5 Apache Commons StringUtils memiliki metode berikut:

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)

Ini memberikan perbandingan String aman nol.


6

Menggunakan 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

Bandingkan dua string menggunakan equals (-, -) dan metode equalsIgnoreCase (-, -) dari kelas 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

Anda bisa menggunakan java.util.Objectssebagai berikut.

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

apakah ini yang kamu inginkan?


5
Kasus ini kembali falsejika kedua Strings nullmungkin bukan hasil yang diinginkan.
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, jadi apa artinya "solusi terbaik"?

Jika yang Anda maksud paling mudah dibaca, maka semua solusi yang mungkin cukup banyak setara untuk seorang programmer Java yang berpengalaman. Tapi IMO yang paling mudah dibaca adalah ini

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

Dengan kata lain, sembunyikan implementasi di dalam metode sederhana yang (idealnya) dapat digarisbawahi.

(Anda juga bisa "out-source" ke perpustakaan utilitas pihak ke-3 ... jika Anda sudah menggunakannya dalam basis kode Anda.)


Jika yang Anda maksud adalah sebagian besar pemain, maka:

  1. solusi yang paling berkinerja tergantung pada platform dan konteksnya,
  2. salah satu "konteks" masalah adalah frekuensi relatif (dinamis) terjadinya nullargumen,
  3. itu mungkin tidak masalah versi yang lebih cepat ... karena perbedaan mungkin terlalu kecil untuk membuat perbedaan untuk kinerja aplikasi secara keseluruhan, dan
  4. jika itu penting, satu-satunya cara untuk mencari tahu mana yang tercepat DI PLATFORM ANDA adalah dengan mencoba kedua versi dan mengukur perbedaannya.
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.