Когда использовать Comparable и Comparator


108

У меня есть список объектов, которые мне нужно отсортировать по полю, например Score. Не задумываясь, я написал новый класс, реализующий Comparator, который выполняет задачу и работает.

Теперь, оглядываясь на это, мне интересно, должен ли я вместо этого иметь мой класс, реализующий Comparable, вместо создания нового класса, который реализует Comparator. Оценка - это единственное поле, по которому будут размещаться объекты.

  1. Что я сделал приемлемым на практике?

  2. Правильный ли подход: «Сначала пусть класс реализует Comparable (для естественного порядка), а если требуется альтернативное сравнение полей, затем создайте новый класс, который реализует Comparator»?

  3. Если (2) выше верно, то означает ли это, что нужно реализовать Comparator только после того, как у них есть реализация класса Comparable? (Предполагая, что у меня есть исходный класс).

Ответы:


80

Я бы сказал, что объект должен реализовывать Comparable, если это очевидный естественный способ сортировки класса, и любой, кому нужно будет сортировать класс, обычно захочет сделать это таким образом.

Если, однако, сортировка была необычным использованием класса или сортировка имеет смысл только для определенного варианта использования, то Comparator - лучший вариант.

Другими словами, с учетом имени класса ясно, как будет сортировать сопоставимый объект, или вам нужно прибегнуть к чтению документации javadoc? Если это последнее, скорее всего, для каждого будущего варианта использования сортировки потребуется компаратор, и в этот момент реализация сопоставимого может замедлить пользователей класса, а не ускорить их.


Не могли бы вы привести небольшой пример?
rgamber 07

это может быть хорошим примером: gist.github.com/yclian/2627608 Существует класс Version, который использует ComparableVersion. Версия - предоставляет фабричные методы. ComparableVersion, как предполагается, является объектом (без статических методов) - предоставляет версию, которую можно сравнить с другой. Обязанности разделены.
ses

2
Вы можете обратиться java-journal.blogspot.in/2011/01/...
обучающийся

Интервьюер спросил, зачем использовать Comparator, когда то же самое можно сделать с Comparable, и я был глуп :(
Aadam

Ссылка @aLearner мертва
G.Brown

127

Используйте, Comparableесли вы хотите определить поведение упорядочивания по умолчанию (естественное) для рассматриваемого объекта, обычной практикой является использование для этого технического или естественного (база данных?) Идентификатора объекта.

Используйте, Comparatorесли вы хотите определить внешнее управляемое поведение упорядочивания, это может переопределить поведение упорядочивания по умолчанию.


3
Это техническое объяснение, и оно настолько правильное, насколько оно возможно, но на самом деле ничего не говорит о лучших практиках.
extraneon

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, имеют интерфейс Comparable.

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

Компараторный объект может сравнивать два разных объекта. Класс сравнивает не свои экземпляры, а экземпляры некоторых других классов. Этот класс компаратора должен реализовывать интерфейс java.util.Comparator.

  • Возможность сравнения любых двух объектов одного типа.
  • Используя это, мы можем реализовать many sort sequenceи назвать каждый в зависимости от свойств экземпляра. EX:Person.id, Person.name, Person.age
  • Мы можем реализовать интерфейс Comparator для наших предопределенных классов для настраиваемой сортировки.

Пример:

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: Comparator см. Мой пост.


10

Comparable следует использовать при сравнении экземпляров одного и того же класса.

Компаратор можно использовать для сравнения экземпляров разных классов.

Comparable реализуется классом, которому необходимо определить естественный порядок для своих объектов. Подобно String реализует Comparable.

Если кто-то хочет другой порядок сортировки, он может реализовать компаратор и определить свой собственный способ сравнения двух экземпляров.


10

Если сортировка объектов должна быть основана на естественном порядке, используйте Comparable, тогда как если ваша сортировка должна выполняться по атрибутам разных объектов, используйте Comparator в Java.

Основные различия между Comparable и 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.        ¦
+------------------------------------------------------------------------------------+

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

Я бы сказал:

  • если сравнение интуитивно понятно, то непременно реализуйте Comparable
  • если неясно, интуитивно ли ваше сравнение, используйте компаратор, поскольку он более явный и, следовательно, более понятный для бедняги, которая должна поддерживать код
  • если возможно более одного интуитивного сравнения, я бы предпочел Comparator, возможно построенный фабричным методом в сравниваемом классе.
  • если сравнение является специальным, используйте Comparator

6

Следующие пункты помогут вам решить, в каких ситуациях следует использовать Comparable и в каком Comparator:

1) Наличие кода

2) Единичный критерий сортировки или множественный критерий сортировки

3) Arays.sort () и Collection.sort ()

4) Как ключи в SortedMap и SortedSet

5) Больше количества занятий по сравнению с гибкостью

6) Межклассовые сравнения

7) Естественный порядок

Для получения более подробной информации вы можете обратиться к Когда использовать сопоставимый, а когда использовать компаратор


Интересно, почему никто не поддерживает этот ответ. Это действительно мило. +1
Diganta 07

4
  • Если на момент написания класса у вас есть только один вариант использования сортировки, используйте Comparable.
  • Только когда у вас есть более одной стратегии сортировки, реализуйте компаратор.

4

Если вам нужна естественная сортировка по порядку - сопоставима с пользователем, если вам нужна сортировка по индивидуальному порядку - используйте компаратор

Пример:

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

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

Ссылки:
Когда класс должен быть Comparable и / или Comparator? http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html


3

Здесь был аналогичный вопрос: когда класс должен быть Comparable и / или Comparator?

Я бы сказал следующее: реализуйте Comparable для чего-то вроде естественного упорядочения, например, на основе внутреннего идентификатора

Внедрите компаратор, если у вас более сложный алгоритм сравнения, например, несколько полей и так далее.


1
Заказ по нескольким полям также может быть выполнен с помощью Comparable.
BalusC

Чтобы узнать разницу между сопоставимым и компаратором, вы можете обратиться к java-journal.blogspot.in/2010/12/…
ученик

2

Сопоставимость:
всякий раз, когда мы хотим хранить только однородные элементы и требуемый естественный порядок сортировки по умолчанию, мы можем использовать comparableинтерфейс реализации класса .

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


0

Мне нужно было отсортировать по дате.

Итак, я использовал Comparable, и у меня это сработало.

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

Одним из ограничений Comparable является то, что они не могут использоваться для других коллекций, кроме List.


0

Если у вас есть класс, лучше выберите Comparable . Обычно Comparator используется, если вы не владеете классом, но вы должны использовать его как TreeSet или TreeMap, потому что Comparator может быть передан как параметр в конструкторе TreeSet или TreeMap. Вы можете увидеть, как использовать Comparator и Comparable в http://preciselyconcise.com/java/collections/g_comparator.php


0

В одном из интервью меня попросили отсортировать определенный диапазон чисел за лучшее, чем nlogn время. (Без использования подсчетной сортировки)

Реализация интерфейса Comparable над объектом позволяет алгоритмам неявной сортировки использовать переопределенный метод compareTo для упорядочивания элементов сортировки, и это будет линейное время.


0

Comparable - это естественный порядок сортировки по умолчанию, обеспечиваемый для числовых значений по возрастанию, а для строк - в алфавитном порядке. например:

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.