El Blog de Ana Buigues » Comparable http://anabuigues.com Wed, 07 Dec 2011 16:07:47 +0000 es-ES hourly 1 http://wordpress.org/?v=3.4 Comparator vs Comparable en Java http://anabuigues.com/2010/09/17/comparator-vs-comparable-en-java/ http://anabuigues.com/2010/09/17/comparator-vs-comparable-en-java/#comments Fri, 17 Sep 2010 16:17:12 +0000 Ana Buigues http://anabuigues.com/?p=1145 Diferencia entre Comparable y Comparator

La diferencia principal entre Comparable y Comparator es que Comparable es utilizado para implementar el orden natural, sin necesidad de especificar un Comparator, por ejemplo, los String son comparados alfabéticamente. Usamos Comparator cuando queramos crear otro tipo de orden que no sea el natural.

El contrato que implica implementar Comparable requiere de un parámetro extra, el objeto con el que comparar compareTo(obj1) de forma que la comparación se realizará del objeto en si (this) con el objeto pasado como parámetro. Comparator, sin embargo obliga a implementar el método compare (obj1, obj2) de forma que los dos objetos a comparar son pasados como parámetros y el objeto que implementa el método compare simplemente sirve de apoyo a la comparación.

Sobreescritura de los métodos compareTo y compare

La forma de sobreescribir estos métodos es muy similar al equals. Los dos métodos cumplen las mismas restricciones que podemos objtener del API de Java:

  • Devolvemos un número negativo si el objeto es menor, devolvemos un cero si es igual y un número positivo si el objeto es mayor.
  • Comparamos el objeto con otro objeto del mismo tipo. Si no son del mismo tipo, lanzamos un ClassCastException.

La notación sgn(expresion) es la función matemática signum, la cual devuelve -1,0, o 1  según sea negativo, zero o positivo

  • Debemos asegurar que: sgn(compare(x,y)) == -sgn(compare(x,y)), para todo x, y. Esto implica que compare(x,y)) lanzará una excepción sii compare(x,y) también la lanza.
  • Debemos asegurar que la relación es transitiva: compare(x,y) > 0 && compare(y,z) > 0 implica que compare(x,z) > 0
  • Debemos asegurar que: compare(x,y) == 0 implica que sgn(compare(x,z)) == sgn(compare(y,z)), para todo z.
  • Se recomienda, aunque no es estrictamente neceario, nos puede evitar poblemas al usar colecciones que implementen esta interfaz. (compare(x,y) == 0) == (x.equals(y))
  • El orden natural para una clase “c”  tiene que ser consistente con el equals si y solo sí: compare(e1,e2) == 0 tiene que ser el mismo resultado que para e1.equals(e2) para cada e1 y e2 de la clase “c”.

Uso de Comparable y Comparator

Podemos usarlos en listas y arrays mediante los métodos Collections.sort y Arrays.sort.También como claves en un mapa ordenado TreeMap o como elementos en un set ordenado TreeSet.

En el caso de Comparable los objetos tienen que implementar esta interfaz para que los ordene automáticamente. Para el caso del Comparator debemos especificar el Comparator.

Ejemplo Comparable

//Ejemplo Comparable
public class Person implements Comparable<Person> {
 private String firstName;
 private String lastName;
 public Person(String firstName, String lastName) {
  if (firstName == null || lastName == null)
   throw new NullPointerException();
  this.firstName = firstName;
  this.lastName = lastName;
 }
 @Override
 public String toString() {
  return String.format("%s, %s", firstName, lastName);
 }
 @Override
 public int compareTo(Person p) {
  int lastCmp = firstName.compareTo(p.firstName);
  return (lastCmp != 0 ? lastCmp : lastName.compareTo(p.lastName));
 }
 public static void main(String[] args) {
  Set<Person> p = new TreeSet<Person>();
  p.add(new Person("Ana", "Rodes"));
  p.add(new Person("Hector", "Lopez"));
  p.add(new Person("Ana", "Buigues"));
  p.add(new Person("Carlitos", "Perez"));
  for (Person person : p)
   System.out.println(person);
 }
}

La salida será:
Ana, Buigues
Ana, Rodes
Carlitos, Perez
Hector, Lopez

Ejemplos Comparator

//Ejemplo Comparator
public class LengthComparator implements Comparator<Person> {
 @Override
 public int compare(Person p1, Person p2) {
  if (p1.toString().length() < p2.toString().length())
   return 1;
  else if (p1.toString().length() > p2.toString().length())
   return -1;
  else
   return 0;
 }
 public static void main(String[] args) {
  List<Person> p = new ArrayList<Person>();
  p.add(new Person("Ana", "Rodes"));
  p.add(new Person("Hector", "Lopez"));
  p.add(new Person("Ana", "Buigues"));
  p.add(new Person("Carlitos", "Perez"));
  Collections.sort(p, new LengthComparator());
  for (Person person : p)
   System.out.println(person);
 }
}

La salida será:
Ana, Rodes
Ana, Buigues
Hector, Lopez
Carlitos, Perez

También lo podemos utilizar de forma anónima

Set<Person> persons = new TreeSet<Person>(new Comparator<Person>() {
  @Override
 public int compare(Person p1, Person p2) {
  if (p1.toString().length() < p2.toString().length())
   return 1;
  else if (p1.toString().length() > p2.toString().length())
   return -1;
  else
   return 0;
 }
});
]]>
http://anabuigues.com/2010/09/17/comparator-vs-comparable-en-java/feed/ 23