Saya menerapkan compareTo()
metode untuk kelas sederhana seperti ini (untuk dapat menggunakan Collections.sort()
dan barang lain yang ditawarkan oleh platform Java):
public class Metadata implements Comparable<Metadata> {
private String name;
private String value;
// Imagine basic constructor and accessors here
// Irrelevant parts omitted
}
Saya ingin urutan alami untuk objek-objek ini adalah: 1) diurutkan berdasarkan nama dan 2) diurutkan berdasarkan nilai jika nama sama; kedua perbandingan harus peka terhadap huruf besar-kecil. Untuk kedua bidang, nilai nol sangat dapat diterima, jadi compareTo
jangan sampai putus dalam kasus ini.
Solusi yang muncul dalam pikiran adalah di sepanjang garis berikut (saya menggunakan "klausa penjaga" di sini sementara yang lain mungkin lebih suka satu titik kembali, tapi itu intinya):
// primarily by name, secondarily by value; null-safe; case-insensitive
public int compareTo(Metadata other) {
if (this.name == null && other.name != null){
return -1;
}
else if (this.name != null && other.name == null){
return 1;
}
else if (this.name != null && other.name != null) {
int result = this.name.compareToIgnoreCase(other.name);
if (result != 0){
return result;
}
}
if (this.value == null) {
return other.value == null ? 0 : -1;
}
if (other.value == null){
return 1;
}
return this.value.compareToIgnoreCase(other.value);
}
Ini berhasil, tapi saya tidak sepenuhnya senang dengan kode ini. Memang itu tidak terlalu rumit, tetapi cukup bertele-tele dan membosankan.
Pertanyaannya adalah, bagaimana Anda membuat ini kurang bertele-tele (sambil mempertahankan fungsi)? Silakan merujuk ke perpustakaan standar Java atau Apache Commons jika mereka membantu. Apakah satu-satunya pilihan untuk membuat ini (sedikit) lebih sederhana adalah dengan mengimplementasikan "NullSafeStringComparator" saya sendiri, dan menerapkannya untuk membandingkan kedua bidang?
Suntingan 1-3 : Eddie benar; memperbaiki kasus "kedua nama adalah nol" di atas
Tentang jawaban yang diterima
Saya menanyakan pertanyaan ini pada tahun 2009, di Java 1.6 tentu saja, dan pada saat itu solusi JDK murni oleh Eddie adalah jawaban yang saya pilih. Saya tidak pernah sempat mengubah itu sampai sekarang (2017).
Ada juga solusi perpustakaan pihak ke-3 - Koleksi Apache Commons 2009 satu dan satu Guava 2013, keduanya diposting oleh saya - yang saya lebih suka di beberapa titik waktu.
Saya sekarang membuat solusi Java 8 bersih oleh Lukasz Wiktor jawaban yang diterima. Itu pasti harus disukai jika di Jawa 8, dan hari ini Java 8 harus tersedia untuk hampir semua proyek.
sumber
Jawaban:
Menggunakan Java 8 :
sumber
Collections.sort(List)
itu tidak berfungsi ketika Daftar berisi nol, komentar itu tidak relevan dengan pertanyaan.Anda cukup menggunakan Apache Commons Lang :
sumber
nullsFirst()
/nullsLast()
.org.apache.commons.lang3
) adalah "warisan / tidak terawat / berkualitas rendah" adalah palsu atau paling tidak tidak berdasar. Commons Lang3 mudah dimengerti dan digunakan, dan itu dipelihara secara aktif. Mungkin pustaka saya yang paling sering digunakan (terlepas dari Spring Framework dan Spring Security) - kelas StringUtils dengan metode null-safe membuat normalisasi input menjadi sepele, misalnya.Saya akan menerapkan pembanding aman nol. Mungkin ada implementasi di luar sana, tetapi ini sangat mudah diterapkan sehingga saya selalu menjalankannya sendiri.
Catatan: Komparator Anda di atas, jika kedua nama adalah nol, bahkan tidak akan membandingkan bidang nilai. Saya tidak berpikir ini yang Anda inginkan.
Saya akan menerapkan ini dengan sesuatu seperti berikut:
EDIT: Memperbaiki kesalahan ketik dalam sampel kode. Itulah yang saya dapatkan karena tidak mengujinya terlebih dahulu!
EDIT: Promosi nullSafeStringComparator ke statis.
sumber
final
kata kunci tidak benar-benar diperlukan (kode Java sudah verbose sebagaimana adanya.) Namun, itu mencegah penggunaan kembali parameter sebagai vars lokal (praktik pengkodean yang mengerikan.) As pemahaman kolektif kita tentang perangkat lunak menjadi lebih baik seiring waktu, kita tahu bahwa segala sesuatunya harus final / const / inmutable secara default. Jadi saya lebih suka sedikit verbositas tambahan dalam menggunakanfinal
dalam deklarasi parameter (namun sepele fungsi mungkin) untuk mendapatkaninmutability-by-quasi-default
.) Kelengkapan biaya overhead / pemeliharaan itu diabaikan dalam skema hal-hal besar.Lihat bagian bawah jawaban ini untuk solusi yang diperbarui (2013) menggunakan Guava.
Inilah yang akhirnya saya ikuti. Ternyata kami sudah memiliki metode utilitas untuk perbandingan String null-safe, jadi solusi paling sederhana adalah memanfaatkannya. (Ini basis kode besar; mudah untuk melewatkan hal semacam ini :)
Ini adalah bagaimana helper didefinisikan (itu kelebihan beban sehingga Anda juga dapat menentukan apakah nulls datang pertama atau terakhir, jika Anda mau):
Jadi ini pada dasarnya sama dengan jawaban Eddie (walaupun saya tidak akan menyebut metode pembantu statis sebagai pembanding ) dan juga dari uzhin .
Bagaimanapun, secara umum, saya akan sangat menyukai solusi Patrick , karena saya pikir itu praktik yang baik untuk menggunakan perpustakaan yang sudah ada kapan pun memungkinkan. ( Ketahui dan gunakan perpustakaan seperti yang dikatakan Josh Bloch.) Tetapi dalam hal ini tidak akan menghasilkan kode yang paling bersih dan paling sederhana.
Edit (2009): Versi Koleksi Apache Commons
Sebenarnya, inilah cara untuk membuat solusi berdasarkan Apache Commons
NullComparator
lebih sederhana. Gabungkan dengan case-insensitive yangComparator
disediakan diString
kelas:Sekarang ini cukup elegan, saya pikir. (Tinggal satu masalah kecil: Commons
NullComparator
tidak mendukung obat generik, jadi ada tugas yang tidak dicentang.)Pembaruan (2013): Versi jambu
Hampir 5 tahun kemudian, inilah cara saya menangani pertanyaan awal saya. Jika pengkodean di Jawa, saya (tentu saja) akan menggunakan Jambu biji . (Dan tentu saja bukan Apache Commons.)
Letakkan konstanta ini di suatu tempat, misalnya di kelas "StringUtils":
Kemudian, di
public class Metadata implements Comparable<Metadata>
:Tentu saja, ini hampir identik dengan versi Apache Commons (keduanya menggunakan JASE CASE_INSENSITIVE_ORDER JDK ), penggunaan
nullsLast()
menjadi satu-satunya hal khusus Guava. Versi ini lebih disukai hanya karena Guava lebih disukai, sebagai ketergantungan, ke Commons Collections. (Karena semua orang setuju .)Jika Anda bertanya-tanya tentang
Ordering
, catatan bahwa alatComparator
. Ini cukup berguna terutama untuk kebutuhan penyortiran yang lebih kompleks, memungkinkan Anda misalnya untuk menggunakan beberapa Pemesanan menggunakancompound()
. Baca Pemesanan Dijelaskan untuk lebih lanjut!sumber
ComparatorChain
maka Anda tidak perlu menggunakancompareTo
metode sendiri .Saya selalu merekomendasikan menggunakan Apache commons karena kemungkinan besar akan lebih baik daripada yang Anda dapat menulis sendiri. Plus Anda kemudian dapat melakukan pekerjaan 'nyata' daripada menciptakan kembali.
Kelas yang Anda minati adalah Null Comparator . Ini memungkinkan Anda untuk membuat nulls tinggi atau rendah. Anda juga memberikan komparator sendiri untuk digunakan saat kedua nilai tersebut bukan nol.
Dalam kasus Anda, Anda dapat memiliki variabel anggota statis yang melakukan perbandingan dan kemudian
compareTo
metode Anda hanya referensi itu.Sesuatu seperti
}
Bahkan jika Anda memutuskan untuk roll sendiri, ingat kelas ini karena sangat berguna ketika memesan daftar yang berisi elemen nol.
sumber
Saya tahu bahwa itu mungkin tidak langsung menjawab pertanyaan Anda, karena Anda mengatakan bahwa nilai nol harus didukung.
Tapi saya hanya ingin mencatat bahwa mendukung nulls di compareTo tidak sejalan dengan kontrak compareTo yang dijelaskan dalam javadocs resmi untuk Comparable :
Jadi saya akan melempar NullPointerException secara eksplisit atau membiarkannya dilemparkan pertama kali ketika argumen nol sedang direferensikan.
sumber
Anda dapat mengekstrak metode:
}
sumber
Anda dapat mendesain kelas Anda agar tidak berubah (Efektif Java 2nd Ed. Memiliki bagian yang hebat tentang hal ini, Butir 15: Minimalkan mutabilitas) dan pastikan pada konstruksi bahwa tidak ada null yang mungkin (dan gunakan pola objek nol jika diperlukan). Kemudian Anda dapat melewati semua cek itu dan dengan aman menganggap bahwa nilainya bukan nol.
sumber
Saya mencari sesuatu yang serupa dan ini tampak agak rumit jadi saya melakukan ini. Saya pikir ini sedikit lebih mudah dimengerti. Anda dapat menggunakannya sebagai pembanding atau sebagai satu liner. Untuk pertanyaan ini, Anda akan mengubah ke compareToIgnoreCase (). Seperti, nulls melayang. Anda dapat membalik 1, -1 jika Anda ingin mereka tenggelam.
.
sumber
kita bisa menggunakan java 8 untuk melakukan perbandingan ramah-null antara objek. seharusnya saya memiliki kelas Boy dengan 2 bidang: Nama string dan Integer age dan saya ingin pertama membandingkan nama dan kemudian usia jika keduanya sama.
dan hasilnya:
sumber
Jika ada yang menggunakan Spring, ada kelas org.springframework.util.comparator.NullSafeComparator yang melakukan ini untuk Anda juga. Hiasi saja sendiri sebanding dengan itu seperti ini
new NullSafeComparator<YourObject>(new YourComparable(), true)
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/comparator/NullSafeComparator.html
sumber
Untuk kasus khusus di mana Anda tahu data tidak akan memiliki nol (selalu ide bagus untuk string) dan datanya sangat besar, Anda masih melakukan tiga perbandingan sebelum benar-benar membandingkan nilai, jika Anda yakin ini adalah kasus Anda , Anda dapat mengoptimalkan sedikit tad. YMMV sebagai kode yang dapat dibaca mengalahkan optimasi kecil:
sumber
output adalah
sumber
Salah satu cara sederhana menggunakan NullSafe Comparator adalah dengan menggunakan implementasi Spring, di bawah ini adalah salah satu contoh sederhana untuk merujuk:
sumber
Contoh Apache ObjectUtils lain. Mampu mengurutkan jenis objek lainnya.
sumber
Ini adalah implementasi saya yang saya gunakan untuk mengurutkan ArrayList saya. kelas nol diurutkan ke yang terakhir.
untuk kasus saya, EntityPhone memperluas EntityAbstract dan wadah saya adalah Daftar <EntityAbstract>.
metode "compareIfNull ()" digunakan untuk pengurutan aman null. Metode lain adalah untuk kelengkapan, menunjukkan bagaimana comparIfNull dapat digunakan.
sumber
Jika Anda ingin Retas sederhana:
Jika Anda ingin meletakkan nulls di akhir daftar, ubah saja ini di metod di atas
sumber