Ordenar Listas en Java

Bien, ordenar una lista en Java, es algo muy sencillo, lo único que tenemos que hacer es llamar al método Sort, de la clase Collections, mandarle cómo parámetro la Lista que queremos ordenar y este los ordenara dado el orden natural del objeto (interfaz Comparable) , y si no queremos eso, pues podemos crear un Comparator. Sin embargo, imaginemos que tenemos aproximadamente unos 20 Objetos diferentes, que son JavaBeans, y que requerimos ordenarlos muchas veces por diferentes propiedades que tengan como por ejemplo Nombre, Apellido Paterno, Apellido Materno o Dirección. Tendríamos que estar creando Comparators para cada una de las propiedades que tenga el JavaBean y de está forma luego ya poder ordenarlos. Tendríamos al menos más de 20 Comparators diferentes que implementan casi la misma lógica, comparar un bean por alguna de sus propiedades, complicado no?. Bueno una solución para esto es el API de Reflection de Java





Bueno para inciar es necesario crear la firma de nuestro método, el cual podemos introducir en una clase Util que tenga métodos que usaremos durante nuestra aplicación, entonces la firma de nuesto método queda así:


import java.util.List;


public class Util {

public static void ordena(List lista, String propiedad) {

}

}

Lo único que hara el método sera recibir una lista, la cual ordenaremos, y la propiedad por la cual queremos ordenarla. Es decir vamos a ordenar una lista de Personas por Edad, entonces lo único que tendríamos que hacer es llamar a nuestro metodo ordena(lista,"nombre"), donde lista, es la Lista de Personas y nombre es una propiedad del JavaBean, es decir tiene métodos de setNombre() y getNombre().



Bien, ahora si pasemos a la parte divertida, para hacer esto, lo único que tenemos que hacer es mandar llamar al metodo Sort de la Clase Collections (la idea original) y crear un Comparator. Sólo que el Comparator, llamara a las propiedades de los objetos en tiempo de ejecución utilizando el API de Reflection de Java. Entonces hasta ahora lo que tenemos es esto:



import java.util.Collections;
import java.util.Comparator;
import java.util.List;


public class Util {

public static void ordena(List lista, String propiedad) {
Collections.sort(lista, new Comparator() {
public int compare(Object arg0, Object arg1) {
return 0;
}
});
}

}






Ahora lo que tenemos que hacer es llamar a los metodos getPropiedad de cada uno de los objetos y compararlos. Esto se logra llamando al método getClass() de la clase Object, luego con esa Clase, llamamaos al método getMethod() y se le manda como pararametro el nombre del método el cual sera getXXXXX donde XXXXX es nuestra propiedad, por ejemplo "nombre" llamara al método getNombre. Y finalmente se invocan esos métodos para obtener las propiedades y luego compararlas. El método invoke() de la clase Method, regresa siempre Object y si el método regresa tipos primitivos regresa su clase encapsuladora (int->Integer etc...).


import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;


public class Util {

public static void ordena(List lista, final String propiedad) {
Collections.sort(lista, new Comparator() {

public int compare(Object obj1, Object obj2) {

Class clase = obj1.getClass();
String getter = "get" + Character.toUpperCase(propiedad.charAt(0)) + propiedad.substring(1);
try {
Method getPropiedad = clase.getMethod(getter);

Object propiedad1 = getPropiedad.invoke(obj1);
Object propiedad2 = getPropiedad.invoke(obj2);

//AUN TENEMOS QUE COMPARARLAS

}
catch(Exception e) {
e.printStackTrace();
}





return 0;
}
});
}


}



Por último solo falta comparar las propiedades, para esto utilizaremos el operador instanceof, para saber si la propiedad es comparable utilizando compareTo(), de lo contrario usaremos el metodo equals para comparar los objetos y si no son iguales regresaremos 1 (Que en realidad esto no es de mucha utilidad de cualquier forma jaja, pero es lo único que se puede hacer). Además al parámetro de la propiedad, tenemos que agregar la opcion final, porque será usado dentro de la clase Comparator que estamos definiendo internamente.



import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;



public class Util {

public static void ordena(List lista, final String propiedad) {
Collections.sort(lista, new Comparator() {

public int compare(Object obj1, Object obj2) {

Class clase = obj1.getClass();
String getter = "get" + Character.toUpperCase(propiedad.charAt(0)) + propiedad.substring(1);
try {
Method getPropiedad = clase.getMethod(getter);

Object propiedad1 = getPropiedad.invoke(obj1);
Object propiedad2 = getPropiedad.invoke(obj2);

if(propiedad1 instanceof Comparable && propiedad2 instanceof Comparable) {
Comparable prop1 = (Comparable)propiedad1;
Comparable prop2 = (Comparable)propiedad2;
return prop1.compareTo(prop2);
}//CASO DE QUE NO SEA COMPARABLE
else {
if(propiedad1.equals(propiedad2))
return 0;
else
return 1;

}

}
catch(Exception e) {
e.printStackTrace();
}
return 0;
}
});
}


}



Bien de esta forma tenemos terminado nuestro método, ahora solo falta probarlo, y para esto crearemos un Main, con una Lista de Objetos de Clase Persona, que son un JavaBean y la Ordenaremos. Además al método agregamos una anotación para que elimine las Warnings y el compilador no este dando lata jaja. Por último nuestra clase luce así:


import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;



public class Util {

@SuppressWarnings("unchecked")
public static void ordena(List lista, final String propiedad) {
Collections.sort(lista, new Comparator() {

public int compare(Object obj1, Object obj2) {

Class clase = obj1.getClass();
String getter = "get" + Character.toUpperCase(propiedad.charAt(0)) + propiedad.substring(1);
try {
Method getPropiedad = clase.getMethod(getter);

Object propiedad1 = getPropiedad.invoke(obj1);
Object propiedad2 = getPropiedad.invoke(obj2);

if(propiedad1 instanceof Comparable && propiedad2 instanceof Comparable) {
Comparable prop1 = (Comparable)propiedad1;
Comparable prop2 = (Comparable)propiedad2;
return prop1.compareTo(prop2);
}//CASO DE QUE NO SEA COMPARABLE
else {
if(propiedad1.equals(propiedad2))
return 0;
else
return 1;

}

}
catch(Exception e) {
e.printStackTrace();
}
return 0;
}
});
}

public static void main(String[] args) {
List<Persona> personas = new ArrayList<Persona>();


personas.add(new Persona("Gustavo",25));
personas.add(new Persona("Pedro",32));
personas.add(new Persona("Pablo",15));
personas.add(new Persona("Juan",10));
personas.add(new Persona("Ramiro",50));
personas.add(new Persona("Daniel",81));
personas.add(new Persona("Hector",23));

System.out.print("Lista sin ordenar:");
System.out.println(personas);
System.out.println();


//LLAMAMOS A ORDENA POR NOMBRE
ordena(personas,"nombre");
System.out.print("Ordenadas por Nombre:");
System.out.println(personas);
System.out.println();

//LLAMAMOS A ORDENA POR EDAD
ordena(personas,"edad");
System.out.print("Ordenadas por Edad:");
System.out.println(personas);
System.out.println();

}


}

class Persona {

String nombre;
int edad;



public Persona(String nombre, int edad) {
super();
this.nombre = nombre;
this.edad = edad;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public int getEdad() {
return edad;
}
public void setEdad(int edad) {
this.edad = edad;
}

//SOLO PARA QUE SEA MAS FACIL VER LOS DATOS
public String toString() {
return nombre + " " + edad;
}

}





Aún habría algunas cosas que agregar a nuestro método, cómo manejo correcto de excepciones, ponerlo en una clase más adecuada etc... Pero en Escencia ya está terminado y lo podremos usar y reusar en muchos de nuestros proyectos!



Espero te haya servido
Saludos


4 comments:

Aldeyta said...

txs it´s a very good way to order a list but if i want include the ascending or descending order?

Gus said...

You can add a boolean parameter, and compare the properties on diferent order, if u want I can write an entry with that.

Thanks for comments!

Unknown said...

/**
* Este metodo permirte ordenar una lista de
* numeros
* sortOrder: variable q determina si ordena
* ascendente o descendente
*/

private static void sortAListNumbers(List datalist, final String sortOrder) {
Collections.sort(datalist, new Comparator() {
public int compare(Object objectA, Object objectB) {

Class clase = objectA.getClass();
try {
Method method = clase.getMethod("intValue");

Object valuePropertyA = method.invoke(objectA);
Object valuePropertyB = method.invoke(objectB);

if (valuePropertyA instanceof Comparable && valuePropertyB instanceof Comparable) {
Comparable comparableA = (Comparable) valuePropertyA;
Comparable comparableB = (Comparable) valuePropertyB;

if(sortOrder.equals("asc")){
return comparableA.compareTo(comparableB);
}else{
if(sortOrder.equals("des")){
if(comparableA.compareTo(comparableB) == 1){
return -1;
}else{
return 1;
}
}
}

}
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
});
}

jsi said...

muy bien pero el tipo de letra es muy pequeño y cuesta trabajo leer

Post a Comment