Kapan menggunakan Comparable dan Comparator

108

Saya memiliki daftar objek yang perlu saya sortir di lapangan, misalnya Score. Tanpa banyak berpikir saya menulis kelas baru yang mengimplementasikan Pembanding, yang melakukan tugas dan berhasil.

Sekarang melihat kembali ini, saya bertanya-tanya apakah saya harus memiliki kelas saya mengimplementasikan Comparable daripada membuat kelas baru yang mengimplementasikan Comparator. Skor adalah satu-satunya bidang tempat objek akan dipesan.

  1. Apa yang telah saya lakukan dapat diterima sebagai praktik?

  2. Apakah pendekatan yang tepat "Pertama, minta kelas mengimplementasikan Sebanding (untuk pengurutan alami) dan jika perbandingan bidang alternatif diperlukan, buatlah kelas baru yang mengimplementasikan Pembanding"?

  3. Jika (2) di atas benar, lalu apakah itu berarti bahwa seseorang harus mengimplementasikan Comparator hanya setelah mereka mengimplementasikan class Comparable? (Dengan asumsi saya memiliki kelas asli).

pkrish
sumber

Jawaban:

80

Saya akan mengatakan bahwa sebuah objek harus mengimplementasikan Comparable jika itu adalah cara alami yang jelas untuk mengurutkan kelas, dan siapa pun yang perlu mengurutkan kelas umumnya ingin melakukannya dengan cara itu.

Namun, jika pengurutan adalah penggunaan kelas yang tidak biasa, atau pengurutan hanya masuk akal untuk kasus penggunaan tertentu, maka Pembanding adalah opsi yang lebih baik.

Dengan kata lain, dengan nama kelasnya, apakah sudah jelas bagaimana penyortiran yang sebanding, atau apakah Anda harus membaca javadoc? Jika itu yang terakhir, kemungkinannya setiap kasus penggunaan penyortiran di masa depan akan membutuhkan pembanding, di mana implementasi yang sebanding dapat memperlambat pengguna kelas, bukan mempercepat mereka.

Yishai
sumber
Bisakah Anda memberi contoh singkat?
rgamber
ini mungkin contoh yang bagus: gist.github.com/yclian/2627608 Ada kelas Versi yang menggunakan ComparableVersion. Versi - menyediakan metode pabrik. ComparableVersion yang seharusnya menjadi objek (tanpa metode statis) - menyediakan versi yang dapat dibandingkan dengan versi lain. Tanggung jawab dipisahkan.
ses
2
Anda dapat merujuk java-journal.blogspot.in/2011/01/…
Pembelajar
Pewawancara bertanya, mengapa menggunakan Comparator padahal hal yang sama bisa dilakukan dengan Comparable, dan saya bodoh :(
Aadam
Tautan @aLearner sudah mati
G. Brown
127

Gunakan Comparablejika Anda ingin mendefinisikan perilaku pengurutan default (alami) dari objek yang dimaksud, praktik yang umum adalah menggunakan pengenal teknis atau alami (database?) Objek untuk ini.

Gunakan Comparatorjika Anda ingin menentukan perilaku pemesanan terkontrol eksternal , ini dapat menggantikan perilaku pemesanan default.

BalusC
sumber
3
Itu adalah penjelasan teknis, dan sama benarnya dengan penjelasan tersebut, tetapi tidak benar-benar menjelaskan apa pun tentang praktik terbaik.
ekstraneon
40
itu memberi tahu kapan harus menggunakan masing-masing - jika itu bukan praktik terbaik, apa itu?
Bozho
1
"Apakah penerapan Comparableberarti saya mendefinisikan tatanan alam?" , ini memberi saya jawaban yang saya cari. Terima kasih :)
Somjit
61

Penggunaan Comparable:

  • jika objek ada dalam kendali Anda.
  • jika perilaku membandingkan adalah perilaku membandingkan utama.

Penggunaan Comparator:

  • jika objek berada di luar kendali Anda dan Anda tidak dapat menerapkannya Comparable.
  • bila Anda ingin membandingkan perilaku yang berbeda dari perilaku default (yang ditentukan oleh Comparable).
Bozho
sumber
20

Sebanding -java.lang.Comparable: int compareTo(Object o1)

Objek yang sebanding mampu membandingkan dirinya dengan objek lain. Kelas itu sendiri harus mengimplementasikan antarmuka java.lang.Comparable agar dapat membandingkan instance-nya.

  • Mampu membandingkan objek saat ini dengan objek yang disediakan.
  • Dengan menggunakan ini kita dapat mengimplementasikan only one sort sequenceberdasarkan properti instance. EX:Person.id
  • Beberapa Kelas yang Ditetapkan Sebelumnya seperti String, kelas Pembungkus, Tanggal, Kalender telah menerapkan antarmuka yang Sebanding.

Pembanding -java.util.Comparator: int compare(Object o1, Object o2)

Sebuah objek pembanding mampu membandingkan dua objek yang berbeda. Kelas tidak membandingkan instance-nya, tetapi beberapa instance kelas lainnya. Kelas pembanding ini harus mengimplementasikan antarmuka java.util.Comparator.

  • Mampu membandingkan dua Objek dengan Jenis yang Sama.
  • Dengan menggunakan ini kita dapat mengimplementasikan many sort sequencedan memberi nama masing-masing, berdasarkan properti instance. EX:Person.id, Person.name, Person.age
  • Kita dapat mengimplementasikan antarmuka pembanding ke kelas yang ditentukan sebelumnya untuk penyortiran yang disesuaikan.

Contoh:

public class Employee implements Comparable<Employee> {

    private int id;
    private String name;
    private int age;
    private long salary;

    // Many sort sequences can be created with different names.
    public static Comparator<Employee> NameComparator = new Comparator<Employee>() {         
        @Override
        public int compare(Employee e1, Employee e2) {
            return e1.getName().compareTo(e2.getName());
        }
    };
    public static Comparator<Employee> idComparator = new Comparator<Employee>() {       
        @Override
        public int compare(Employee e1, Employee e2) {
            return Integer.valueOf(e1.getId()).compareTo(Integer.valueOf(e2.getId()));
        }
    };

    public Employee() { }
    public Employee(int id, String name, int age, long salary){
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    // setters and getters.

    // Only one sort sequence can be created with in the class.
    @Override
    public int compareTo(Employee e) {
    //return Integer.valueOf(this.id).compareTo(Integer.valueOf(e.id));
    //return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
        if (this.id > e.id) {
            return 1;
        }else if(this.id < e.id){
            return -1;
        }else {
            return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
        }

    }   

    public static void main(String[] args) {

        Employee e1 = new Employee(5, "Yash", 22, 1000);
        Employee e2 = new Employee(8, "Tharun", 24, 25000);

        List<Employee> list = new ArrayList<Employee>();
        list.add(e1);
        list.add(e2);
        Collections.sort(list); // call @compareTo(o1)
        Collections.sort(list, Employee.nameComparator); // call @compare (o1,o2)
        Collections.sort(list, Employee.idComparator); // call @compare (o1,o2)
    }
}
  • Untuk penyortiran yang disesuaikan, kami menggunakan komparator @compare (o1, o2) untuk skenario lain kami menggunakan @compareTo (o1) yang sebanding, tanpa mengubah kode jika kami ingin mengurutkan lebih dari satu bidang maka kami menggunakan pembanding.

Untuk Java 8 Lambda: Pembanding lihat posting saya.

Yash
sumber
10

Comparable harus digunakan saat Anda membandingkan instance dari kelas yang sama.

Pembanding dapat digunakan untuk membandingkan instance dari kelas yang berbeda.

Comparable diimplementasikan oleh kelas yang perlu mendefinisikan tatanan natural untuk objeknya. Seperti String mengimplementasikan Comparable.

Jika seseorang menginginkan urutan pengurutan yang berbeda maka dia dapat menerapkan pembanding dan menentukan caranya sendiri untuk membandingkan dua contoh.

Devang Paliwal
sumber
10

Jika pengurutan objek harus didasarkan pada tatanan natural maka gunakan Comparable sedangkan jika pengurutan Anda perlu dilakukan pada atribut objek yang berbeda, gunakan Comparator di Java.

Perbedaan utama antara Comparable dan Comparator:

+------------------------------------------------------------------------------------+
¦               Comparable                ¦                Comparator                ¦
¦-----------------------------------------+------------------------------------------¦
¦ java.lang.Comparable                    ¦ java.util.Comparator                     ¦
¦-----------------------------------------+------------------------------------------¦
¦ int objOne.compareTo(objTwo)            ¦ int compare(objOne, objTwo)              ¦
¦-----------------------------------------+------------------------------------------¦
¦ Negative, if objOne < objTwo            ¦ Same as Comparable                       ¦
¦ Zero,  if objOne == objTwo              ¦                                          ¦
¦ Positive,  if objOne > objTwo           ¦                                          ¦
¦-----------------------------------------+------------------------------------------¦
¦ You must modify the class whose         ¦ You build a class separate from to sort. ¦
¦ instances you want to sort.             ¦ the class whose instances you want       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Only one sort sequence can be created   ¦ Many sort sequences can be created       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Implemented frequently in the API by:   ¦ Meant to be implemented to sort          ¦
¦ String, Wrapper classes, Date, Calendar ¦ instances of third-party classes.        ¦
+------------------------------------------------------------------------------------+
Joby Wilson Mathews
sumber
9

Pembanding melakukan semua hal yang sebanding, ditambah lagi.

| | Comparable | Comparator ._______________________________________________________________________________ Is used to allow Collections.sort to work | yes | yes Can compare multiple fields | yes | yes Lives inside the class you’re comparing and serves | | as a “default” way to compare | yes | yes Can live outside the class you’re comparing | no | yes Can have multiple instances with different method names | no | yes Input arguments can be a list of | just Object| Any type Can use enums | no | yes

Saya menemukan pendekatan terbaik untuk menggunakan komparator sebagai kelas anonim sebagai berikut:

private static void sortAccountsByPriority(List<AccountRecord> accounts) {
    Collections.sort(accounts, new Comparator<AccountRecord>() {

        @Override
        public int compare(AccountRecord a1, AccountRecord a2) {
            return a1.getRank().compareTo(a2.getRank());
        }
    });
}

Anda dapat membuat beberapa versi dari metode tersebut langsung di dalam kelas yang Anda rencanakan untuk disortir. Jadi, Anda dapat memiliki:

  • sortAccountsByPriority
  • sortAccountsByType
  • sortAccountsByPriorityAndType

    dll ...

Sekarang, Anda dapat menggunakan metode pengurutan ini di mana saja dan mendapatkan kode yang digunakan kembali. Ini memberi saya segala sesuatu yang sebanding, ditambah lebih banyak ... jadi saya tidak melihat alasan untuk menggunakan yang sebanding sama sekali.


sumber
8

Saya akan mengatakan:

  • jika perbandingannya intuitif, maka implementasikanlah Comparable
  • jika tidak jelas apakah perbandingan Anda intuitif, gunakan Pembanding karena lebih eksplisit dan dengan demikian lebih jelas bagi jiwa malang yang harus memelihara kode
  • jika ada lebih dari satu perbandingan intuitif yang mungkin, saya lebih suka Pembanding, mungkin dibangun dengan metode pabrik di kelas untuk dibandingkan.
  • Jika perbandingannya bertujuan khusus, gunakan Comparator
extraneon
sumber
6

Poin-poin berikut membantu Anda dalam memutuskan di situasi mana seseorang harus menggunakan Comparable dan di mana Comparator:

1) Ketersediaan Kode

2) Kriteria Penyortiran Tunggal versus Banyak

3) Arays.sort () dan Collection.sort ()

4) Sebagai kunci di SortedMap dan SortedSet

5) Lebih Banyak Jumlah Kelas versus Fleksibilitas

6) Perbandingan antar kelas

7) Tatanan Alami

Untuk artikel yang lebih rinci, Anda dapat merujuk Kapan menggunakan sebanding dan kapan menggunakan komparator

seorang Pembelajar
sumber
Saya bertanya-tanya mengapa tidak ada yang menyukai jawaban ini. Itu sangat bagus. +1
Diganta
4
  • Jika pada saat menulis kelas Anda hanya memiliki satu use case dari pengurutan, gunakan Comparable.
  • Hanya jika Anda memiliki lebih dari satu strategi pengurutan, terapkan Pembanding.
fabrizioM
sumber
4

Jika Anda memerlukan penyortiran urutan alami - Dapat Dibandingkan Pengguna JIKA Anda memerlukan Penyortiran Pesanan Kustom - Gunakan Pembanding

Contoh:

Class Employee{
private int id;
private String name;
private String department;
}

Penyortiran tatanan natural akan didasarkan pada id karena akan unik dan penyortiran pesanan khusus adalah nama dan departemen.

Refrensi:
Kapan sebuah kelas menjadi Comparable dan / atau Comparator? http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html

Rajiv
sumber
3

Ada pertanyaan serupa di sini: Kapan sebuah kelas menjadi Comparable dan / atau Comparator?

Saya akan mengatakan yang berikut: Menerapkan Sebanding untuk sesuatu seperti pemesanan alami, misalnya berdasarkan ID internal

Terapkan Comparator jika Anda memiliki algoritme pembanding yang lebih kompleks, misalnya banyak bidang dan sebagainya.

ZeissS
sumber
1
Memesan di berbagai bidang bisa dilakukan sebaik mungkin Comparable.
BalusC
Untuk perbedaan antara pembanding dan pembanding, Anda dapat merujuk java-journal.blogspot.in/2010/12/…
Pelajar
2

Sebanding:
Kapan pun kita ingin menyimpan hanya elemen homogen dan urutan alami default diperlukan, kita dapat menggunakan comparableantarmuka implementasi kelas .

Pembanding:
Setiap kali kami ingin menyimpan elemen homogen dan heterogen dan kami ingin mengurutkan dalam urutan penyortiran kustom default, kami dapat menggunakan comparatorantarmuka.

G swamy reddy
sumber
0

Kebutuhan saya diurutkan berdasarkan tanggal.

Jadi, saya menggunakan Comparable dan itu bekerja dengan mudah untuk saya.

public int compareTo(GoogleCalendarBean o) {
    // TODO Auto-generated method stub
    return eventdate.compareTo(o.getEventdate());
}

Satu batasan dengan Comparable adalah bahwa mereka tidak dapat digunakan untuk Koleksi selain Daftar.

musim semi pro
sumber
0

Jika Anda memiliki kelas lebih baik pergi dengan Comparable . Umumnya Comparator digunakan jika Anda tidak memiliki kelas tetapi Anda harus menggunakannya TreeSet atau TreeMap karena Comparator dapat dikirimkan sebagai parameter dalam pembuat TreeSet atau TreeMap. Anda dapat melihat cara menggunakan Comparator dan Comparable di http:// prec tepatnyaconcise.com/java/collections/g_comparator.php

Sai Sunder
sumber
0

Saya telah diminta untuk menyortir kisaran angka tertentu dengan lebih baik daripada waktu yang diketahui dalam salah satu wawancara. (Tidak menggunakan jenis Penghitungan)

Mengimplementasikan antarmuka Comparable di atas objek memungkinkan algo pengurutan implisit menggunakan metode bandingkanTo yang diganti untuk mengurutkan elemen sortir dan itu akan menjadi waktu linier.

Mr Wonderful
sumber
0

Comparable adalah urutan pengurutan alami default yang disediakan untuk nilai numerik menaik dan untuk string adalah urutan abjad. misalnya:

Treeset t=new Treeset();
t.add(2);
t.add(1);
System.out.println(t);//[1,2]

Pembanding adalah urutan pengurutan kustom yang diterapkan di kelas myComparator kustom dengan mengganti metode perbandingan untuk misalnya:

Treeset t=new Treeset(new myComparator());
t.add(55);
t.add(56);
class myComparator implements Comparator{
public int compare(Object o1,Object o2){
//Descending Logic
}
}
System.out.println(t);//[56,55]
Ajay Takur
sumber
-1

Pendekatan yang sangat sederhana adalah dengan mengasumsikan bahwa kelas entitas yang dimaksud direpresentasikan dalam database dan kemudian dalam tabel database, apakah Anda memerlukan indeks yang terdiri dari bidang kelas entitas? Jika jawabannya ya, terapkan pembanding dan gunakan bidang indeks untuk urutan pengurutan alami. Dalam semua kasus lain gunakan pembanding.

pengguna976715
sumber
-2

Lib anotasi saya untuk menerapkan Comparabledan Comparator:

public class Person implements Comparable<Person> {         
    private String firstName;  
    private String lastName;         
    private int age;         
    private char gentle;         

    @Override         
    @CompaProperties({ @CompaProperty(property = "lastName"),              
        @CompaProperty(property = "age",  order = Order.DSC) })           
    public int compareTo(Person person) {                 
        return Compamatic.doComparasion(this, person);         
    }  
}

Klik link untuk melihat lebih banyak contoh. http://code.google.com/p/compamatic/wiki/CompamaticByExamples

Jianmin Liu
sumber