Коли використовувати Comparable та Comparator


108

У мене є список об'єктів, які мені потрібно сортувати на полі, скажімо Score. Не замислюючись, я написав новий клас, який реалізує компаратор, який виконує завдання і він працює.

Тепер, озираючись на це, мені цікаво, чи повинен я мій клас мати реалізацію класу Comparable замість створення нового класу, який реалізує компаратор. Оцінка - єдине поле, на яке будуть замовлені об’єкти.

  1. Що я зробив прийнятним як практика?

  2. Чи правильний підхід "Спочатку запропонуйте клас реалізувати Порівняльний (для природного впорядкування), і якщо потрібне альтернативне порівняння поля, то створіть новий клас, який реалізує компаратор"?

  3. Якщо (2) вище істинно, то чи означає це, що слід застосовувати компаратор лише після того, як у них буде клас реалізувати Порівняльний? (Припустимо, що я володію оригінальним класом).

Відповіді:


80

Я б сказав, що об’єкт повинен реалізовувати Порівняння, якщо це зрозумілий природний спосіб сортування класу, і будь-кому потрібно сортувати клас, як правило, він хотів би зробити це саме так.

Якщо ж сортування було незвичним використанням класу, або сортування має сенс лише для конкретного випадку використання, то порівняльний варіант - кращий варіант.

По-іншому, з огляду на назву класу, чи зрозуміло, як би порівняти порівняння, чи вам доведеться вдаватися до читання javadoc? Якщо це останнє, шанси - кожен майбутній випадок використання сортування потребує порівняння, і тоді реалізація порівнянних може уповільнити користувачів класу, а не прискорити їх.


Чи можете ви надати короткий приклад?
rgamber

це може бути хорошим прикладом: gist.github.com/yclian/2627608 Існує клас версій, який використовує ComparableVersion. Версія - надає заводські методи ComparableVersion, який повинен бути об'єктом (без статичних методів) - надає версію, яку можна порівняти з іншою. Обов’язки розділені.
SES

2
ви можете посилатись на java-journal.blogspot.in/2011/01/…
учень

Інтерв'юер запитав, навіщо використовувати компаратор, коли те ж саме можна зробити з Порівняльним, і я був німий :(
Aadam

Посилання @aLearner мертве
G.Brown

127

Використовуйте, Comparableякщо ви хочете визначити типовий (природний) порядок впорядкування відповідного об'єкта, звичайною практикою є використання для цього технічного або природного (бази даних?) Ідентифікатора.

Використовуйте, Comparatorякщо ви хочете визначити зовнішню поведінку впорядкування з замовленням, це може змінити поведінку замовлення за замовчуванням.


3
Це технічне пояснення і настільки ж правильне, наскільки вони приходять, але насправді нічого не говорить про кращі практики.
екстранеон

40
це говорить про те, коли використовувати кожен - якщо це не найкраща практика, що це?
Божо

1
"Чи Comparableозначає здійснення, що я визначаю природний порядок?" , це дало мені відповідь, яку я шукав. Дякую :)
Somjit

61

Використовуйте Comparable :

  • якщо об’єкт знаходиться під вашим контролем.
  • якщо порівнююча поведінка є основною поведінкою, що порівнює.

Використання Comparator:

  • якщо об’єкт знаходиться поза вашим контролем, і ви не можете змусити їх реалізувати Comparable .
  • коли ви хочете порівнювати поведінку, відмінну від поведінки за замовчуванням (що задається Comparable).

20

Порівняння -java.lang.Comparable: int compareTo(Object o1)

Порівнюваний об'єкт здатний порівнювати себе з іншим об'єктом. Сам клас повинен реалізувати інтерфейс java.lang.Comparable, щоб можна було порівнювати його екземпляри.

  • Здатний порівнювати поточний об'єкт із наданим об'єктом.
  • Використовуючи це, ми можемо реалізувати only one sort sequenceна основі властивостей екземплярів. EX:Person.id
  • Деякі із заздалегідь визначених класів, такі як String, Wrapper-класи, Date, Calendar, реалізували порівнянний інтерфейс.

Компаратор -java.util.Comparator: int compare(Object o1, Object o2)

Об'єкт порівняння здатний порівнювати два різні об'єкти. Клас не порівнює його екземпляри, а деякі інстанції класу. Цей клас порівняння повинен реалізувати інтерфейс java.util.Comparator.

  • Здатний порівнювати будь-які два об'єкти одного типу.
  • Використовуючи це, ми можемо реалізувати many sort sequenceта називати кожен, виходячи із властивостей екземплярів. EX:Person.id, Person.name, Person.age
  • Ми можемо реалізувати інтерфейс компаратора до наших попередньо визначених класів для індивідуального сортування.

Приклад:

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)
    }
}
  • Для спеціалізованого сортування ми використовуємо компаратор @compare (o1, o2) для інших сценаріїв, ми використовуємо порівнянний @compareTo (o1), без зміни коду, якщо ми хочемо сортувати більше одного поля, то використовуємо компаратор.

Для Java 8 Lambda: Компаратор див. Моє повідомлення.


10

Порівняння слід використовувати при порівнянні екземплярів одного класу.

Порівняльник можна використовувати для порівняння примірників різних класів.

Порівняльне реалізується класом, якому потрібно визначити природне впорядкування для його об'єктів. Як і рядкові інструменти порівнянні.

Якщо ви хочете іншого порядку сортування, то він може застосувати компаратор та визначити власний спосіб порівняння двох примірників.


10

Якщо сортування об'єктів має базуватися на природному порядку, тоді використовуйте Порівняння, тоді як якщо сортування потрібно проводити за атрибутами різних об'єктів, тоді використовуйте компаратор на Java.

Основні відмінності між Порівняльним та Порівняльним:

+------------------------------------------------------------------------------------+
¦               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.        ¦
+------------------------------------------------------------------------------------+

9

Компаратор робить усе, що робить порівнянне, плюс більше.

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

Я знайшов найкращий підхід використовувати компаратори як анонімні класи таким чином:

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

Можна створити кілька версій таких методів прямо в класі, який ви плануєте сортувати. Отже, ви можете мати:

  • sortAccountsByPriority
  • sortAccountsByType
  • sortAccountsByPriorityAndType

    тощо ...

Тепер ви можете використовувати ці способи сортування в будь-якому місці та отримати повторне використання коду. Це дає мені все, що можна порівняти, плюс більше ... тому я не бачу жодної причини використовувати порівнянне взагалі.


8

Я б сказав:

  • якщо порівняння інтуїтивно зрозуміле, то будь-якими способами реалізуйте Порівняльне
  • якщо незрозуміло, чим ваше порівняння є інтуїтивно зрозумілим, використовуйте компаратор, оскільки він більш явний і, таким чином, більш зрозумілий для бідної душі, яка має підтримувати код
  • якщо можливе більш ніж одне інтуїтивне порівняння, я вважаю за краще порівняльник, можливо, побудований фабричним методом у класі для порівняння.
  • якщо порівняння має спеціальне призначення, використовуйте компаратор

6

Наступні моменти допоможуть вам вирішити, в яких ситуаціях слід використовувати Порівняльний та в якому Порівняльний:

1) Доступність коду

2) Єдиний проти кількох критеріїв сортування

3) Arays.sort () і Collection.sort ()

4) Як ключі в SortedMap та SortedSet

5) Більше Кількість класів Від гнучкості

6) Міжкласові порівняння

7) Природний порядок

Для більш детальної статті ви можете посилатися Коли використовувати порівняльний та коли використовувати компаратор


Цікаво, чому ніхто не підтримує цю відповідь. Це дійсно приємно. +1
Diganta

4
  • Якщо на момент написання класу у вас є лише один випадок використання сортування, порівняльний.
  • Тільки коли у вас є кілька стратегій сортування, застосуйте компаратор.

4

Якщо вам потрібне природне сортування замовлень - Користувач порівняно, якщо вам потрібна спеціальна сортування замовлень - використовуйте компаратор

Приклад:

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

Сортування природного порядку базувалося б на ідентифікаторі, оскільки це було б унікальним, а на замовлення сортуванням було б назва та відділ.

Відгуки:
Коли клас повинен бути порівнянним та / або порівняльним? http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html


3

Тут виникало подібне питання: Коли клас повинен бути порівнянним та / або порівняльним?

Я б сказав наступне: Реалізація Порівняльна для чогось подібного до природного замовлення, наприклад на основі внутрішнього ідентифікатора

Використовуйте компаратор, якщо у вас складніший алгоритм порівняння, наприклад, декілька полів тощо.


1
Замовлення в декількох полях може бути так само добре Comparable.
BalusC

Для різниці між порівнянним та порівняльним можна звернутися до java-journal.blogspot.in/2010/12/…
учень

2

Порівняно:
Щоразу, коли ми хочемо зберігати лише однорідні елементи та необхідний природний порядок сортування за замовчуванням, ми можемо перейти до comparableінтерфейсу впровадження класу .

Компаратор:
Щоразу, коли ми хочемо зберігати однорідні та неоднорідні елементи, і ми хочемо сортувати за замовчуванням індивідуальний порядок сортування, ми можемо перейти до comparatorінтерфейсу.


0

Моя потреба була сортована за датою.

Отже, я використав Порівняння, і це легко працювало на мене.

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

Одне обмеження для Порівняння полягає в тому, що вони не можуть використовуватися для колекцій, крім Списку.


0

Якщо ви володієте класом, краще перейдіть із Порівняльним . Як правило, компаратор використовується, якщо ви не володієте класом, але вам доведеться використовувати його TreeSet або TreeMap, оскільки компаратор може бути переданий як параметр у конвекторі TreeSet або TreeMap. Дізнатися, як використовувати "Порівняння" та "Порівняння", ви можете дізнатися на веб-сторінці http://preciselyconcise.com/java/collections/g_comparator.php


0

В одному з інтерв'ю мене попросили сортувати певний діапазон чисел за кращий ніж nlogn час. (Не використовується сортування підрахунку)

Реалізація Порівнюваного інтерфейсу над об'єктом дозволяє неявним сортуванням альго для використання заміненого методу CompareTo для впорядкування елементів сортування, і це буде лінійний час.


0

Порівнюваний природний порядок сортування за замовчуванням, передбачений для числових значень, збільшується, а рядки - за алфавітом. наприклад:

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

Компаратор - це спеціальний порядок сортування, реалізований у користувальницькому класі myComparator, замінивши метод порівняння, наприклад:

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]

-1

Дуже простий підхід полягає в тому, щоб припустити, що відповідний клас сутності представлений у базі даних, а потім у таблиці бази даних, чи потрібен би вам індекс, що складається з полів класу сутності? Якщо відповідь "так", тоді застосуйте порівнянне та використовуйте поля (поля) індексу для природного порядку сортування. У всіх інших випадках використовуйте компаратор.


-2

Моя анотація для впровадження Comparableта 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);         
    }  
}

Клацніть посилання, щоб побачити більше прикладів. http://code.google.com/p/compamatic/wiki/CompamaticByExamples

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.