简体   繁体   English

何时使用 Comparable 和 Comparator

[英]When to use Comparable and Comparator

I have a list of objects I need to sort on a field, say Score.我有一个需要在字段上排序的对象列表,比如 Score。 Without giving much thought I wrote a new class that implements Comparator, that does the task and it works.我没有多想就写了一个实现 Comparator 的新类,它可以完成任务并且可以工作。

Now looking back at this, I am wondering if I should have instead have the my class implement Comparable instead of creating a new class that implements Comparator.现在回想起来,我想知道我是否应该让我的类实现 Comparable,而不是创建一个实现 Comparator 的新类。 The score is the only field that the objects will be ordered on.分数是唯一可以对对象进行排序的字段。

  1. What I have done acceptable as a practice?我做了什么可以接受的做法?

  2. Is the right approach "First have the class implement Comparable (for the natural ordering) and if an alternative field comparison is required, then create a new class that implements Comparator" ?正确的方法是“首先让类实现 Comparable(用于自然排序),如果需要替代字段比较,然后创建一个实现 Comparator 的新类”?

  3. If (2) above is true, then does it mean that one should implement Comparator only after they have the class implement Comparable?如果上面的(2)是正确的,那么是否意味着只有在类实现了 Comparable 之后才应该实现 Comparator ? (Assuming I own the original class). (假设我拥有原始类)。

UseComparable if you want to define a default (natural) ordering behaviour of the object in question, a common practice is to use a technical or natural (database?) identifier of the object for this.如果要定义所讨论对象的默认(自然)排序行为,请使用Comparable ,通常的做法是为此使用对象的技术或自然(数据库?)标识符。

UseComparator if you want to define an external controllable ordering behaviour, this can override the default ordering behaviour.如果要定义外部可控排序行为,请使用Comparator ,这可以覆盖默认排序行为。

I would say that an object should implement Comparable if that is the clear natural way to sort the class, and anyone would need to sort the class would generally want to do it that way.我会说一个对象应该实现 Comparable 如果这是对类进行排序的清晰自然的方式,并且任何需要对类进行排序的人通常都希望这样做。

If, however, the sorting was an unusual use of the class, or the sorting only makes sense for a specific use case, then a Comparator is a better option.但是,如果排序是类的不寻常使用,或者排序仅对特定用例有意义,那么 Comparator 是更好的选择。

Put another way, given the class name, is it clear how a comparable would sort, or do you have to resort to reading the javadoc?换句话说,给定类名,是否清楚可比较的排序方式,还是必须求助于阅读 javadoc? If it is the latter, odds are every future sorting use case would require a comparator, at which point the implementation of comparable may slow down users of the class, not speed them up.如果是后者,很可能每个未来的排序用例都需要比较器,此时可比较的实现可能会减慢该类的用户的速度,而不是加快他们的速度。

Use Comparable :使用Comparable

  • if the object is in your control.如果对象在您的控制之下。
  • if the comparing behaviour is the main comparing behaviour.如果比较行为是主要的比较行为。

Use Comparator :使用Comparator

  • if the object is outside your control and you cannot make them implement Comparable .如果对象不在您的控制范围内并且您无法使它们实现Comparable
  • when you want comparing behaviour different from the default (which is specified by Comparable ) behaviour.当您想要比较与默认行为(由Comparable指定)不同的行为时。

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

A comparable object is capable of comparing itself with another object.可比较对象能够将自身与另一个对象进行比较。 The class itself must implements the java.lang.Comparable interface in order to be able to compare its instances.类本身必须实现 java.lang.Comparable 接口才能比较其实例。

  • Capable of comparing current object with the provided object.能够将当前对象与提供的对象进行比较。
  • By using this we can implement only one sort sequence based on the instances properties.通过使用它,我们可以only one sort sequence实现only one sort sequence基于实例属性的only one sort sequence EX: Person.id例如: Person.id
  • Some of the Predefined Classes like String, Wrapper classes, Date, Calendar has implemented Comparable interface.一些预定义类,如 String、Wrapper 类、Date、Calendar 已经实现了 Comparable 接口。

Comparator - java.util.Comparator: int compare(Object o1, Object o2) 比较器- java.util.Comparator: int compare(Object o1, Object o2)

A comparator object is capable of comparing two different objects.比较器对象能够比较两个不同的对象。 The class is not comparing its instances, but some other class's instances.该类不是比较它的实例,而是比较其他一些类的实例。 This comparator class must implement the java.util.Comparator interface.这个比较器类必须实现 java.util.Comparator 接口。

  • Capable of comparing any two Objects of Same Type.能够比较任何两个相同类型的对象。
  • By using this we can implement many sort sequence and name each, based on the instances properties.通过使用它,我们可以基于实例属性实现many sort sequence并命名每个。 EX: Person.id, Person.name, Person.age例如: Person.id, Person.name, Person.age
  • We can implement Comparator interface to our Pre-defined classes for Customized sorting.我们可以为我们的预定义类实现 Comparator 接口以进行自定义排序。

Example:例子:

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)
    }
}
  • For customized sorting we go for comparator @compare(o1, o2) for other scenarios we go for comparable @compareTo(o1), with out changing code if we want to sort more than one field then we use comparator.对于自定义排序,我们使用比较器 @compare(o1, o2) 对于其他场景,我们使用可比较的 @compareTo(o1),如果我们想要对多个字段进行排序,则无需更改代码,然后我们使用比较器。

For Java 8 Lambda : Comparator refer to my post.对于Java 8 Lambda:比较器,请参阅我的帖子。

Comparable should be used when you compare instances of the same class.当您比较同一类的实例时,应使用 Comparable。

Comparator can be used to compare instances of different classes.比较器可用于比较不同类的实例。

Comparable is implemented by the class which needs to define a natural ordering for its objects. Comparable 由需要为其对象定义自然顺序的类实现。 For example, String implements Comparable.例如,String 实现了 Comparable。

In case a different sorting order is required, then, implement comparator and define its own way of comparing two instances.如果需要不同的排序顺序,则实现比较器并定义自己的比较两个实例的方式。

If sorting of objects needs to be based on natural order then use Comparable whereas if your sorting needs to be done on attributes of different objects, then use Comparator in Java.如果对象的排序需要基于自然顺序,则使用 Comparable,而如果需要对不同对象的属性进行排序,则使用 Java 中的 Comparator。

Main differences between Comparable and Comparator: 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.        ¦
+------------------------------------------------------------------------------------+

Comparator does everything that comparable does, plus more. Comparator 可以完成可比较所做的一切,而且还有更多。

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

I found the best approach to use comparators as anonymous classes as follows:我发现使用比较器作为匿名类的最佳方法如下:

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

You can create multiple versions of such methods right inside the class you're planning to sort.您可以在您计划排序的类中创建此类方法的多个版本。 So you can have:所以你可以有:

  • sortAccountsByPriority按优先级排序帐户
  • sortAccountsByType按类型排序帐户
  • sortAccountsByPriorityAndType sortAccountsByPriorityAndType

    etc...等等...

Now, you can use these sort methods anywhere and get code reuse.现在,您可以在任何地方使用这些排序方法并获得代码重用。 This gives me everything a comparable would, plus more ... so I don't see any reason to use comparable at all.这给了我可比的一切,再加上更多......所以我根本看不到任何使用可比性的理由。

I would say:我会说:

  • if the comparison is intuitive, then by all means implement Comparable如果比较直观,那么一定要实现 Comparable
  • if it is unclear wether your comparison is intuitive, use a Comparator as it's more explicit and thus more clear for the poor soul who has to maintain the code如果不清楚您的比较是否直观,请使用比较器,因为它更明确,因此对于必须维护代码的可怜人来说更清晰
  • if there is more than one intuitive comparison possible I'd prefer a Comparator, possibly build by a factory method in the class to be compared.如果可能有多个直观的比较,我更喜欢比较器,可能由要比较的类中的工厂方法构建。
  • if the comparison is special purpose, use Comparator如果比较是特殊目的,请使用 Comparator

The following points help you in deciding in which situations one should use Comparable and in which Comparator:以下几点可以帮助您决定在哪些情况下应该使用 Comparable 以及在哪种 Comparator 中使用:

1) Code Availabilty 1) 代码可用性

2) Single Versus Multiple Sorting Criteria 2) 单与多排序标准

3) Arays.sort() and Collection.sort() 3) Arays.sort() 和 Collection.sort()

4) As keys in SortedMap and SortedSet 4) 作为 SortedMap 和 SortedSet 中的键

5) More Number of classes Versus flexibility 5)更多的类与灵活性

6) Interclass comparisions 6) 类间比较

7) Natural Order 7) 自然秩序

For more detailed article you can refer When to use comparable and when to use comparator有关更详细的文章,您可以参考何时使用可比较以及何时使用比较器

  • If at the moment of writing the class you have only one use case of sorting use Comparable.如果在编写课程时您只有一个排序用例,请使用 Comparable。
  • Only when you have more than one strategy of sorting implement a Comparator.只有当您有多个排序策略时,才实施 Comparator。

If you need natural order sorting -- User Comparable IF you need Custom Order Sorting - Use Comparator如果您需要自然顺序排序 - User Comparable 如果您需要自定义顺序排序 - 使用比较器

Example:例子:

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

Natural order Sorting would be based on id because it would be unique and custom order sortin g would be name and department.自然顺序排序将基于 id,因为它是唯一的,而自定义顺序排序将是姓名和部门。

Refrences:参考资料:
When should a class be Comparable and/or Comparator? 什么时候类应该是 Comparable 和/或 Comparator? http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html

There had been a similar question here: When should a class be Comparable and/or Comparator?这里曾经有一个类似的问题: 一个类什么时候应该是 Comparable 和/或 Comparator?

I would say the following: Implement Comparable for something like a natural ordering, eg based on an internal ID我会说以下内容:为诸如自然排序之类的东西实现 Comparable,例如基于内部 ID

Implement a Comparator if you have a more complex comparing algorithm, eg multiple fields and so on.如果您有更复杂的比较算法,例如多个字段等,请实现 Comparator。

Comparable:可比:
Whenever we want to store only homogeneous elements and default natural sorting order required, we can go for class implementing comparable interface.每当我们只想存储同类元素和所需的默认自然排序顺序时,我们可以使用实现comparable接口的类。

Comparator:比较器:
Whenever we want to store homogeneous and heterogeneous elements and we want to sort in default customized sorting order, we can go for comparator interface.每当我们想要存储同质和异质元素并且我们想要按照默认的自定义排序顺序进行排序时,我们可以使用comparator接口。

My need was sort based on date.我的需求是根据日期排序的。

So, I used Comparable and it worked easily for me.所以,我使用了 Comparable,它对我来说很容易。

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

One restriction with Comparable is that they cannot used for Collections other than List. Comparable 的一个限制是它们不能用于列表以外的集合。

If you own the class better go with Comparable .如果您拥有该课程,则最好使用Comparable Generally Comparator is used if you dont own the class but you have to use it a TreeSet or TreeMap because Comparator can be passed as a parameter in the conctructor of TreeSet or TreeMap.一般比较使用,如果你不拥有一流的,但你必须使用一个TreeSetTreeMap的,因为比较可以在TreeSet中或树形图conctructor参数传递。 You can see how to use Comparator and Comparable in http://preciselyconcise.com/java/collections/g_comparator.php您可以在http://preciselyconcise.com/java/collections/g_comparator.php 中看到如何使用 Comparator 和 Comparable

I have been asked sorting of a definite range of numbers in better than nlogn time in one of interview.在一次面试中,我被要求在比 nlogn 更好的时间内对一定范围的数字进行排序。 (Not using Counting sort) (不使用计数排序)

Implementing Comparable interface over an object allows implicit sorting algos to use overridden compareTo method to order sort elements and that would be linear time.在对象上实现 Comparable 接口允许隐式排序算法使用重写的 compareTo 方法对元素排序,这将是线性时间。

Comparable is the default natural sorting order provided for numerical values are ascending and for strings are alphabetical order. Comparable 是为数值提供的默认自然排序顺序是升序,字符串是按字母顺序。 for eg:例如:

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

Comparator is the custom sorting order implemented in custom myComparator class by overriding a compare method for eg: Comparator 是在自定义 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]

Very simple approach is to assume that the entity class in question be represented in database and then in database table would you need index made up of fields of entity class?非常简单的方法是假设有问题的实体类在数据库中表示,然后在数据库表中您是否需要由实体类的字段组成的索引? If answer is yes then implement comparable and use the index field(s) for natural sorting order.如果答案是肯定的,则实现可比较并使用索引字段进行自然排序。 In all other cases use comparator.在所有其他情况下使用比较器。

My annotation lib for implementing Comparable and Comparator :我用于实现ComparableComparator注释库:

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

Click the link to see more examples.单击链接以查看更多示例。 http://code.google.com/p/compamatic/wiki/CompamaticByExamples http://code.google.com/p/compamatic/wiki/CompamaticByExamples

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM