FUNDAMENTOS DE PROGRAMACIÓN Curso: 2010/11 PRÁCTICA 14: CRITERIOS DE COMPARACIÓN Y ORDERING Versión: 1.0.3 OBJETIVOS Criterios de comparación auxiliar: Comparator/compare. Utilización de la clase Ordering de la librería Guava. INTERFAZ COMPARATOR VS COMPARABLE Interfaz Comparable En el cuatrimestre anterior hemos diseñado tipos en los que se especificaba un criterio de orden natural, es decir, es el criterio por el que normalmente se comparan los objetos instanciados del tipo en el mundo real. Recordemos que para implementar el criterio de orden natural es necesario: 1. Indicar que la Comparable<T>: interfaz del tipo a implementar extiende la interfaz public interface Nombre_Interfaz extends Comparable<Nombre_Interfaz> { ... } 2. Como consecuencia, en la clase que implemente la interfaz será necesario construir el método int compareTo (T o): public class Nombre_Clase implements Nombre_Interfaz { ... public int compareTo (Nombre_Interfaz o){..} } Además, tenga en cuenta que: El método compareTo devolverá un entero negativo, cero o positivo dependiendo de si el objeto “this” con el que se invoca al método, es menor, igual o mayor al objeto “o” pasado por parámetro. La implementación del método compareTo debe ser coherente con la implementación del método equals, de tal forma que si “o1” y “o2” son dos objetos, entonces se debe de cumplir que si o1.equals(o2) devuelve true entonces o1.compareTo(o2) debe devolver cero. Interfaz Comparator Además de ordenación natural, nos podría interesar ordenar los objetos de un tipo por otros criterios, por ejemplo, el tipo Persona por DNI o también por edad. Para definir estos nuevos criterios de ordenación que son auxiliares y distintos al orden natural se utiliza la interfaz Comparator, que se encuentra definida en el paquete java.util. En este caso, para implementar el criterio de orden natural es necesario: 1. Construir tantas clases nuevas que implementen la interfaz Comparator como criterios de ordenación se deseen public interface Comparator<T> { int compare (T o1, T o2); } Práctica 14: Criterios de Comparación y Ordering 2 El método compare, se comporta de manera similar al método compareTo en cuanto a lo que devuelve, que será un entero negativo, cero o positivo según sea su primer argumento “o1”, menor, igual o mayor al segundo argumento “o2”. Note la diferencia de sintaxis entre los dos métodos: mientras compareTo se invoca por un objeto y se le pasa el otro como parámetro, compare recibe los dos objetos a comparar como argumentos y se invoca con un objeto, creado por defecto, de la clase comparadora. LIBRERÍA GUAVA La librería Guava proporciona un conjunto de utilidades de Google. Esta librería ha sido utilizada en los proyectos internos de Google y la idea que subyace, al hacer pública dicha librería, es la de proveer código basado en buenas prácticas que aumenten la productividad de los desarrolladores. Guava integra también lo que anteriormente era Google Collections, unificando las utilidades de entrada/salida, primitivas, concurrencia y colecciones en una única librería. De todas las utilidades proporcionadas en Guava, nos centramos en la utilización de la clase Ordering. Esta clase combina Comparators con la funcionalidad de Collections. La clase Ordering se utilizará si se necesita ordenar iterables, encontrar el máximo o mínimo en un iterable, encontrar el índice de un elemento del iterable, etc. La documentación de esta clase (API) se encuentra en el enlace: http://guava-libraries.googlecode.com/svn/tags/release08/javadoc/index.html En el siguiente cuadro se observa un resumen de la funcionalidad de la clase Ordering, en el paquete com.google.common.collect.Ordering; static <T> Ordering<T> static Ordering<Object> static <C extends Comparable> Ordering<C> <E extends T> List<E> int <S extends T> Ordering<S> <S extends T> Ordering<S> from(Comparator<T> comparator) Devuelve un ordering para un comparator existente. usingToString() Devuelve un ordering que compara objetos según el orden alfabético de la representación en cadena (toString) de los objetos del iterable que se utilice posteriormente. natural() Devuelve un ordering en función del orden natural, es decir, del método compareTo. sortedCopy(Iterable<E> iterable) Devuelve una copia ordenada de un iterable dado. El orden del iterable depende del criterio de comparación asociado al objeto ordering que invoque este método. binarySearch(List<? extends T> sortedList, T key) Devuelve la posición del element key en el iterable ordenado sortedList utilizando el algoritmo de búsqueda binaria. nullsFirst() Devuelve un ordering que trata iterables con elementos null, de manera que éstos se consideran menores al resto de objetos, si se ordena los elementos null quedarán al principio. nullsLast() Similar al anterior, pero los elementos null quedarán al final del iterable si este es ordenado. Práctica 14: Criterios de Comparación y Ordering <E extends T> E <E extends T> E 3 max(Iterable<E> iterable) Devuelve el máximo del iterable de acuerdo con el criterio de ordenación asociado al objeto ordering que invoca este método. min(Iterable<E> iterable) Devuelve el mínimo del iterable de acuerdo con el criterio de ordenación asociado al objeto ordering que invoca este método. Tenga en cuenta que la clase Ordering tiene un único constructor protegido, es decir, su nivel de visibilidad no es público. Por ello, para crear objetos de tipo Ordering se ha de utilizar uno de los tres métodos estáticos siguientes: El método from, que construye un objeto Ordering en función de un criterio de comparación auxiliar, es decir, un objeto Comparator. Comparator<Persona> c = new ComparadorPorEdad(); Ordering<Persona> ord1 = Ordering.from(c); El método usingToString, que construye un objeto Ordering cuyo criterio de comparación asociado es el alfabético de la representación en cadena de los objetos a ordenar. Ordering<Object> ord2 = Ordering.usingToString(); El método natural, que construye un objeto Ordering cuyo criterio de comparación es el criterio natural. Ordering<Persona> ord3 = Ordering.natural(); EJERCICIOS PROPUESTOS Importe el proyecto Practica14Alumno que se proporciona con la práctica. Dicho proyecto tiene implementado entre otros los tipos Vuelo y Cancion. Tipo Vuelo Codigo, Integer mayor que cero, sólo consultable Destino, String, sólo consultable Precio, Double, consultable y modificable NumeroDePlazas, Integer mayor que cero, sólo consultable NumeroDePasajeros, Integer mayor o igual que cero y menor o igual que NumeroDePlazas, sólo consultable Pasajeros, Vector<Persona>, sólo consultable Fecha, Fecha, posterior a 1/1/2000, sólo consultable Orden natural: por Destino y Codigo Criterio de Igualdad: si tienen el mismo Destino y Codigo Tipo Canción: Nombre, de tipo String, consultable Intérprete, de tipo String, consultable Duración, de tipo Hora, consultable Año, de tipo Integer, consultable Género, de tipo String, consultable Práctica 14: Criterios de Comparación y Ordering 4 NúmeroDeReproducciones, de tipo Integer, consultable y modificable Calificación, de tipo Integer, consultable y modificable (la calificación es un valor que indica cuánto nos gusta una canción y está comprendido entre 0, muy poco, y 5, mucho) Reproducir, de tipo Boolean, consultable y modificable Orden natural: por nombre, y a igualdad de nombre por intérprete Criterio de igualdad: dos canciones son iguales si tienen el mismo nombre y el mismo intérprete Representación como cadena: [Nombre, intérprete] Abra la vista de tareas, en el menú Window->Show View->Tasks, y realice las tareas indicadas con la etiqueta TODO ejercicio X. Descomente estas líneas una vez realizada la tarea que corresponde con los siguientes ejercicios: 1. En el paquete de nombre comparadores implemente para el tipo Vuelo los siguientes criterios de orden auxiliares: a. Criterio de comparación basado en la fecha de Vuelo. b. Según precio de los objetos de Vuelo. 2. En la clase TestVuelos, a partir de la lista proporcionado de nombre vuelos: a. Ordene dicho iterable según su criterio de orden natural y muéstrelo por pantalla. b. Ordene el iterable según el criterio de orden auxiliar basado en la fecha del vuelo y muéstrelo por pantalla. c. Finalmente, ordene el iterable de vuelos según el criterio de orden auxiliar basado en el precio. 3. Añada los siguientes criterios de orden auxiliar al tipo Cancion: a. Criterio auxiliar basado en el año de la canción. b. Criterio auxiliar basado en el género. c. Criterio auxiliar basado en la duración. 4. En la clase TestMusica: a. Ordene la lista proporcionado según el criterio de orden natural del tipo Cancion y muéstrelo por pantalla. b. Ordene la lista de canciones según los criterios del ejercicio anterior. 5. Téngase en cuenta que en Java los criterios de comparación natural son coherentes con el criterio de igualdad, sin embargo los comparadores auxiliares o adicionales que hemos realizado no son coherentes con la igualdad. En ocasiones, puede que el criterio de comparación de un Comparator tenga que ser coherente con el criterio de igualdad. Por ejemplo, piense en un conjunto ordenado al que añadimos objetos de tipo Persona teniendo en cuenta un comparador basado en el año de nacimiento. Al añadir los objetos de manera ordenada el conjunto se basa en el método compare de la clase Comparador y no en el equals. ¿Qué pasaría? Tan solo se añade un objeto de todos los que haya con el mismo año de nacimiento. Haga coherente el criterio criterio de comparación de Vuelo por fecha con el criterio de orden natural que es coherente al equals por definición. Para continuar los ejercicios de la práctica debe importar la librería Guava de Google. Con este objetivo entre en la siguiente dirección donde se encuentra la librería: http://code.google.com/p/guava-libraries/ Haga clic a la derecha del navegador en “Downloads guava-r08.zip” y así podrá descargar el fichero guava-r08.zip. En el espacio de trabajo de su proyecto almacene dicho fichero Práctica 14: Criterios de Comparación y Ordering 5 descomprimido. Al descomprimir aparecerá la carpeta guava-r08 y dentro de ella la librería con el nombre guava-r08.jar Este fichero es la librería que se ha de importar en el proyecto de la práctica, para ello: Seleccionando el proyecto (en el explorador de paquetes”) y con el botón derecho, seleccione “Properties” “Java Build Path”. Seleccione “add External Jar” y seleccione en la ventana de explorador de ficheros el fichero guava-r08.jar. Finalmente, pinche el botón “OK” y en el explorador de paquetes debe aparecer la librería en el proyecto sobre el que estamos trabajando. 6. En la clase utilidad Canciones escriba cada uno de los siguientes métodos estáticos y pruebe su correcto funcionamiento en la clase TestOrdering: a. Dada una lista de canciones y un comparador de Cancion basado en el año de publicación de la canción, devuelva una lista ordenada de la lista. Para ello cree un objeto de tipo Ordering a partir del comparador y el método sortedCopy. public static List<Cancion> creaCopiaIterableOrdenadaAux (List<Cancion> listaCanciones, Comparator<Cancion> c) b. Dada una lista de canciones, cree un objeto de tipo Ordering cuyo criterio de orden será la representación en cadena de los objetos del iterable. Cree una copia ordenada de la lista y devuelva dicha copia como resultado. public static List<Cancion> (List<Cancion> listaCanciones) creaCopiaIterableOrdString c. Dada una lista de canciones, devuelva una copia de la lista ordenada según el criterio de orden natural y utilizando la clase Ordering. public static List<Cancion> (List<Cancion> listaCanciones) creaCopiaIterOrdenadaNat d. Dada una lista de canciones y un objeto de tipo Cancion, devuelva la posición de dicha canción según el orden obtenido a partir del criterio de orden natural. public static int listaCanciones, Cancion c) busquedaDeCancion(List<Cancion> e. Dada una lista que contiene elementos nulos, cree una copia de la lista ordenado según su criterio de orden natural y con los elementos nulos al principio del iterable. public static List <Cancion> (List<Cancion> listaCanciones) f. ordenaNulosPrimeros Dada una lista que contiene elementos nulos, cree una copia de la lista iterable ordenada según su criterio de orden natural y con los elementos nulos al final del iterable. public static List <Cancion> (List<Cancion> listaCanciones) ordenaNulosUltimos g. Dada una lista de canciones devuelva la canción más antigua. public static listaCanciones) Cancion cancionMasAntigua(List<Cancion> h. Realice el ejercicio 6.a pero para una lista genérica. public static <T> List<T> creaCopiaIterableOrdenadaAux2 (List<T> listaT, Comparator<T> c)