Cuándo usar Comparable y Comparator


108

Tengo una lista de objetos que necesito ordenar en un campo, digamos Score. Sin pensarlo mucho, escribí una nueva clase que implementa Comparator, que hace la tarea y funciona.

Ahora, mirando hacia atrás en esto, me pregunto si debería haber hecho que mi clase implemente Comparable en lugar de crear una nueva clase que implemente Comparator. La puntuación es el único campo en el que se ordenarán los objetos.

  1. ¿Qué he hecho aceptable como práctica?

  2. ¿Es el enfoque correcto "Primero haga que la clase implemente Comparable (para el orden natural) y si se requiere una comparación de campo alternativa, entonces cree una nueva clase que implemente Comparator"?

  3. Si (2) anterior es verdadero, entonces ¿significa que uno debe implementar Comparator solo después de que la clase implemente Comparable? (Suponiendo que soy dueño de la clase original).

Respuestas:


80

Yo diría que un objeto debería implementar Comparable si esa es la forma natural clara de ordenar la clase, y cualquiera que necesite ordenar la clase generalmente querrá hacerlo de esa manera.

Sin embargo, si la clasificación fue un uso inusual de la clase, o la clasificación solo tiene sentido para un caso de uso específico, entonces un Comparador es una mejor opción.

Dicho de otra manera, dado el nombre de la clase, ¿está claro cómo se clasificaría un comparable, o tiene que recurrir a leer el javadoc? Si es lo último, lo más probable es que cada caso de uso de clasificación futuro requiera un comparador, momento en el que la implementación de comparable puede ralentizar a los usuarios de la clase, no acelerarlos.


¿Puede dar un ejemplo rápido?
Jueves

este podría ser un buen ejemplo: gist.github.com/yclian/2627608 Hay una clase Version que usa ComparableVersion. Versión: proporciona métodos de fábrica. ComparableVersion se supone que es un objeto (sin métodos estáticos): proporciona una versión que se puede comparar con otra. Las responsabilidades están separadas.
Ses


El entrevistador preguntó, por qué usar Comparator cuando se puede hacer lo mismo con Comparable, y yo era tonto :(
Aadam

@aLearner link is dead
G.Brown

127

Úselo Comparablesi desea definir un comportamiento de ordenamiento predeterminado (natural) del objeto en cuestión, una práctica común es usar un identificador técnico o natural (¿base de datos?) Del objeto para esto.

Úselo Comparatorsi desea definir un comportamiento de pedido controlable externo , esto puede anular el comportamiento de pedido predeterminado.


3
Esa es una explicación técnica, y tan correcta como parece, pero realmente no dice nada sobre las mejores prácticas.
Extraneon

40
indica cuándo usar cada uno; si esa no es una práctica recomendada, ¿cuál es?
Bozho

1
"¿Implementar Comparablesignifica que estoy definiendo el orden natural?" , esto me dio la respuesta que estaba buscando. Gracias :)
Somjit

61

Utilizar Comparable:

  • si el objeto está bajo su control.
  • si el comportamiento de comparación es el principal comportamiento de comparación.

Utilizar Comparator:

  • si el objeto está fuera de su control y no puede hacer que se implementen Comparable.
  • cuando desee comparar un comportamiento diferente del comportamiento predeterminado (que está especificado por Comparable).

20

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

Un objeto comparable es capaz de compararse con otro objeto. La clase en sí debe implementar la interfaz java.lang.Comparable para poder comparar sus instancias.

  • Capaz de comparar el objeto actual con el objeto proporcionado.
  • Al usar esto, podemos implementar en only one sort sequencefunción de las propiedades de las instancias. EX:Person.id
  • Algunas de las clases predefinidas como cadena, clases de envoltura, fecha, calendario han implementado una interfaz comparable.

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

Un objeto comparador es capaz de comparar dos objetos diferentes. La clase no está comparando sus instancias, sino las instancias de alguna otra clase. Esta clase de comparador debe implementar la interfaz java.util.Comparator.

  • Capaz de comparar dos objetos del mismo tipo.
  • Al usar esto, podemos implementar many sort sequencey nombrar cada uno, según las propiedades de las instancias. EX:Person.id, Person.name, Person.age
  • Podemos implementar la interfaz Comparator en nuestras clases predefinidas para una clasificación personalizada.

Ejemplo:

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)
    }
}
  • Para la clasificación personalizada, optamos por el comparador @compare (o1, o2) para otros escenarios, optamos por el @compareTo (o1) comparable, sin cambiar el código si queremos ordenar más de un campo, entonces usamos el comparador.

Para Java 8 Lambda: Comparator, consulte mi publicación.


10

Comparable debe usarse cuando se comparan instancias de la misma clase.

El comparador se puede utilizar para comparar instancias de diferentes clases.

Comparable se implementa por clase que necesita definir un orden natural para sus objetos. Como String implementa Comparable.

En caso de que uno desee un orden de clasificación diferente, puede implementar el comparador y definir su propia forma de comparar dos instancias.


10

Si la clasificación de objetos debe basarse en el orden natural, use Comparable, mientras que si su clasificación debe realizarse en atributos de diferentes objetos, use Comparator en Java.

Principales diferencias entre Comparable y 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

Comparator hace todo lo que hace comparable, y más.

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

Encontré el mejor enfoque para usar comparadores como clases anónimas de la siguiente manera:

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

Puede crear varias versiones de dichos métodos dentro de la clase que planea ordenar. Entonces puedes tener:

  • sortAccountsByPriority
  • sortAccountsByType
  • sortAccountsByPriorityAndType

    etc ...

Ahora, puede usar estos métodos de clasificación en cualquier lugar y obtener la reutilización del código. Esto me da todo lo que sería comparable, y más ... así que no veo ninguna razón para usar algo comparable en absoluto.


8

Yo diría:

  • si la comparación es intuitiva, entonces por todos los medios implemente Comparable
  • Si no está claro si su comparación es intuitiva, use un Comparador, ya que es más explícito y, por lo tanto, más claro para el pobre que tiene que mantener el código.
  • si hay más de una comparación intuitiva posible, preferiría un Comparador, posiblemente construido por un método de fábrica en la clase a comparar.
  • si la comparación tiene un propósito especial, use Comparator

6

Los siguientes puntos le ayudarán a decidir en qué situaciones se debe usar Comparable y en qué Comparator:

1) Disponibilidad del código

2) Criterios de clasificación únicos versus múltiples

3) Arays.sort () y Collection.sort ()

4) Como claves en SortedMap y SortedSet

5) Más cantidad de clases versus flexibilidad

6) Comparaciones entre clases

7) Orden natural

Para obtener un artículo más detallado, puede consultar Cuándo usar comparador y cuándo usar comparador


Me pregunto por qué nadie está votando a favor de esta respuesta. Es realmente bueno. +1
Diganta

4
  • Si en el momento de escribir la clase solo tiene un caso de uso de clasificación, use Comparable.
  • Solo cuando tenga más de una estrategia de clasificación, implemente un Comparador.

4

Si necesita una clasificación de orden natural - Usuario comparable SI necesita una clasificación de orden personalizada - Utilice Comparador

Ejemplo:

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

La clasificación por orden natural se basaría en la identificación porque sería única y la clasificación por orden personalizado sería el nombre y el departamento.

Referencias: ¿
Cuándo debería una clase ser Comparable y / o Comparadora? http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html


3

Aquí había habido una pregunta similar: ¿ Cuándo debería una clase ser Comparable y / o Comparador?

Yo diría lo siguiente: Implementar Comparable para algo así como un orden natural, por ejemplo, basado en un ID interno

Implemente un Comparador si tiene un algoritmo de comparación más complejo, por ejemplo, múltiples campos, etc.


1
Hacer pedidos en varios campos también se puede hacer Comparable.
BalusC

Para conocer la diferencia entre comparable y comparador, puede consultar java-journal.blogspot.in/2010/12/…
un alumno

2

Comparable:
Siempre que queramos almacenar solo elementos homogéneos y el orden de clasificación natural predeterminado requerido, podemos optar por la comparableinterfaz de implementación de clases .

Comparador:
Siempre que queramos almacenar elementos homogéneos y heterogéneos y queramos ordenarlos en un orden de clasificación personalizado predeterminado, podemos optar por la comparatorinterfaz.


0

Mi necesidad se basó en la fecha.

Entonces, usé Comparable y funcionó fácilmente para mí.

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

Una restricción con Comparable es que no se pueden usar para colecciones que no sean List.



0

Me han pedido que clasifique un rango definido de números en un tiempo mejor que nlogn en una de las entrevistas. (No se usa el ordenamiento por conteo)

La implementación de la interfaz Comparable sobre un objeto permite que los algoritmos de clasificación implícitos utilicen el método compareTo reemplazado para ordenar los elementos de clasificación y eso sería un tiempo lineal.


0

Comparable es el orden de clasificación natural predeterminado proporcionado para valores numéricos ascendentes y para cadenas en orden alfabético. por ejemplo:

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

Comparator es el orden de clasificación personalizado implementado en la clase myComparator personalizada anulando un método de comparación para, por ejemplo:

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

Un enfoque muy simple es asumir que la clase de entidad en cuestión está representada en la base de datos y luego en la tabla de la base de datos, ¿necesitaría un índice compuesto por campos de la clase de entidad? Si la respuesta es sí, implemente comparable y use los campos de índice para el orden de clasificación natural. En todos los demás casos, utilice el comparador.


-2

Mi biblioteca de anotaciones para implementar Comparabley 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);         
    }  
}

Haga clic en el enlace para ver más ejemplos. http://code.google.com/p/compamatic/wiki/CompamaticByExamples

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.