Está en la página 1de 25

Tema 9

Colecciones y clases genéricas


Colecciones

Tabla de contenidos
1 Clases genéricas 3
1.1 Implementación de clases genéricas 3
1.2 Instanciación de clases genéricas 4
1.3 Otras formas de especificar tipos genéricos 4

Tema 9 - Colecciones
2 Colecciones 6
2.1 API Collections (java.util.Collections) 7
2.2 Colecciones lineales (List) 8
2.3 Colecciones sin elementos repetidos (Set) 10
2.4 Colecciones clave-valor (Map) 11

3 Iteradores 14
3.1 Métodos de un iterador 14
3.2 Utilización de iteradores 14

4 Localización e identificación de objetos 16


4.1 Los métodos equals() y hashCode() 16
4.2 Influencia de equals() y hashCode() en una colección 18

5 Interfaces Comparable y Comparator 20


5.1 Comparable 20
5.2 Comparator 20
5.3 Ordenar una lista 20

6 Anexo - Clase Persona 24

7 Referencias 25

Programación 2 I.E.S. Luis Vélez de Guevara


Colecciones Clases genéricas

1 Clases genéricas
Se trata de una clase parametrizada sobre uno o más tipos. Las clases genéricas nos evitan
duplicar clases que administran tipos de datos distintos, pero implementan algoritmos o
una lógica similar. Veamos un ejemplo:

Si quisiéramos crear una clase que nos permitiera almacenar objetos de distinto tipo,
podríamos implementar el siguiente código:

Tema 9 - Colecciones
public class Caja {
private Object objeto;

public void guardar(Object objecto) {


this.objeto = objecto;
}

public Object extraer() {


return objeto;
}
}

Sin embargo, este tipo de implementaciones son problemáticas, entre otras razones, por
las siguientes:

▪ Como todas las clases heredan de object, es fácil pasar de manera inadvertida un
objeto de una clase que no se espera.
▪ Al recuperar un objeto, nos vemos continuamente obligados a realizar castings.

Para solucionarlo, a partir Java SE 5 aparecen las clases genéricas.

1.1 Implementación de clases genéricas


Una mejor implementación del ejemplo anterior sería la siguiente:

public class Caja<T> {


private T objeto;

public void guardar(T objeto) {


this.objeto = objeto;
}

public T extraer() {
return objeto;
}
}

Programación 3 I.E.S. Luis Vélez de Guevara


Colecciones Clases genéricas

Es posible utilizar tantos tipos parametrizados como queramos:

public class Par<T, S> {


private T obj1;
private S obj2;
// Resto de la clase
}

Los nombres de tipos de parámetros más usados son:

Tema 9 - Colecciones
▪ E (element, elemento)
▪ K (key, clave)
▪ N (number, número)
▪ T (type, tipo)
▪ V (value, valor)
▪ S, U, V, ... (segundo, tercer, cuarto... tipo)

1.2 Instanciación de clases genéricas


Para instanciar un objeto genérico, tenemos que indicar los tipos dos veces.

Par<String, String> pareja2 = new Par<String, String>("Hola", "Mundo");

Este estilo implica escribir demasiado. Desde Java SE 7 tenemos el operador <>

(diamond).

Par<String, String> pareja2 = new Par<>("Hola", "Mundo");

1.3 Otras formas de especificar tipos genéricos


Podemos indicar que el tipo parametrizado sea uno en particular (o sus derivados).

public class CajaNumerica<T extends Number> {


private T objeto;
// Resto de la clase
}

También podemos indicar más de un tipo, aunque solo uno de ellos puede ser una clase.
El resto deben ser interfaces.

La clase a extender debe ser la primera de la lista.

Programación 4 I.E.S. Luis Vélez de Guevara


Colecciones Clases genéricas

public class A {
// Resto de la clase
}

public interface B {
// Resto de la interfaz
}

public class CajaRara<T extends A & B> {


// Resto de la interfaz
}

Los tipos parametrizados nos permiten relajar el tipo concreto de una clase genérica a un

Tema 9 - Colecciones
subtipo. Esto es útil con colecciones. Por ejemplo, la siguiente función espera recibir una
lista de objetos descendientes de la clase Number ( Byte, Double, Float, Integer,
Long, Short).

public static double sumarLista(List<? extends Number> lista) {


double suma = 0.0;

for (Number n : lista)


suma += n.doubleValue();

return suma;
}

También se puede utilizar <? super T> para indicar que el tipo esperado debe ser un
ancestro de otro. De modo que, por ejemplo:

▪ List<? extends T> representa una lista de la que podremos obtener ejemplares
de T.
▪ List<? super T> representa una lista en la que podremos guardar ejemplares de
T.

Con el siguiente ejemplo se puede ver más claramente la diferencia entre <? super T> y
<? extends T>:

// Válido: se pueden sacar Objects de List<String>


List<? extends Object> a = new ArrayList<String>();
// No válido: no se puede garantizar que List<Object> contenga únicamente Strings
List<? extends String> b = new ArrayList<Object>();

// Válido: se pueden poner Strings dentro de List<Object>


List<? super String> a = new ArrayList<Object>();
// Inválido: no se puede poner Objects en una List<String>
List<? super Object> b = new ArrayList<String>();

Programación 5 I.E.S. Luis Vélez de Guevara


Colecciones Colecciones

2 Colecciones
Una colección en Java es una estructura de datos que permite almacenar muchos valores
del mismo tipo; por tanto, conceptualmente es prácticamente igual que un array. Según el
uso y según si se permiten o no repeticiones, Java dispone de un amplio catálogo de
colecciones: ArrayList (lista), ArrayBlockingQueue (cola), HashSet (conjunto),
Stack (pila), etc.

Las clases que implementan las interfaces de colecciones suelen tener nombres en forma

Tema 9 - Colecciones
de <Implementación-Estilo><Interfaz> . Las implementaciones de propósito general se
resumen en la siguiente tabla:

Hash Resizable Balanced Linked Hash Table +


Interface
Table Array Tree List Linked List
Set HashSet TreeSet LinkedHashSet
List ArrayList LinkedList
Queue,
ArrayDeque LinkedList
Deque
Map HashMap TreeMap LinkedHashMap

Programación 6 I.E.S. Luis Vélez de Guevara


Colecciones Colecciones

2.1 API Collections ( java.util.Collections)


Esta API de Java, disponible desde Java SE 2, nos permite trabajar con colecciones de
datos. Se compone de:

▪ Interfaces: son los distintos tipos de colecciones.


▪ Implementaciones: concreciones de las diferentes interfaces.
▪ Algoritmos: para realizar operaciones como ordenación, búsqueda, etc.

Tema 9 - Colecciones
Todas las colecciones están definidas como genéricas.

Tipos de colecciones

List

▪ Permite implementar listas.


▪ Lineal.
▪ Posibilidad de orden.
▪ Con repetidos.

Set

▪ Permite implementar conjuntos.


▪ No soporta duplicados.
▪ Posibilidad de orden de elementos.

Programación 7 I.E.S. Luis Vélez de Guevara


Colecciones Colecciones

Map

▪ Permite implementar diccionarios.


▪ Estructura clave-valor.
▪ Posibilidad de orden de elementos.

2.2 Colecciones lineales (List)

Tema 9 - Colecciones
Interfaz List

▪ Los elementos tienen posición.


▪ Permite duplicados.
▪ También permite búsqueda e iteraciones.
▪ Las implementaciones más conocidas son ArrayList y LinkedList.
▪ Si no sabemos cual escoger, utilizaremos siempre ArrayList.

Operaciones con una List

Algunas de las operaciones más frecuentes son:

▪ List.of(elemento1, elemento2...): Método estático que permite crear una lista


inmutable con entre 0 y 10 elementos.
▪ add(elemento): Añade un elemento al final la lista.
▪ add(indice, elemento): Inserta un elemento en una posición determinada,
desplazando el resto de elementos hacia la derecha.
▪ addAll(coleccion): Añade todos los elementos de la colección pasada como
argumento.
▪ get(indice): Devuelve el elemento de la posición especificada de la lista.
▪ indexOf(elemento): Devuelve la posición de la primera ocurrencia del elemento
que se indica entre paréntesis.
▪ remove(indice): Elimina un elemento de la lista.
▪ remove(elemento): Elimina la primera ocurrencia de un elemento.
▪ removeIf(filtro): Elimina los elementos que cumplen una determinada condición.
▪ contains(elemento): Comprueba si un elemento está o no en la lista.
▪ isEmpty(): Verifica si la lista está vacía.
▪ set(indice, elemento): Sobreescribe el elemento que se encuentra en una
determinada posición con el elemento que se pasa como parámetro.

Programación 8 I.E.S. Luis Vélez de Guevara


Colecciones Colecciones

▪ clear(): Elimina todos los elementos de la lista.


▪ size(): Devuelve el número de elementos de la lista.
▪ toArray(): Devuelve la lista como un array.

La clase ArrayList

Un ArrayList es una estructura en forma de lista que permite almacenar elementos del
mismo tipo (pueden ser incluso objetos); su tamaño va cambiando a medida que se
añaden o se eliminan esos elementos.

Tema 9 - Colecciones
Nos podemos imaginar un ArrayList como un conjunto de celdas donde se guardan los
valores, exactamente igual que un array convencional. En la práctica será más fácil
trabajar con un ArrayList.

En capítulos anteriores hemos podido comprobar la utilidad del array; es un recurso


imprescindible que cualquier programador debe manejar con soltura. No obstante, el
array presenta algunos inconvenientes. Uno de ellos es la necesidad de conocer el tamaño
exacto en el momento de su creación. Una colección, sin embargo, se crea sin que se tenga
que especificar el tamaño; posteriormente se van añadiendo y quitando elementos a
medida que se necesitan.

Trabajando con arrays es frecuente cometer errores al utilizar los índices; por ejemplo al
intentar guardar un elemento en una posición que no existe (índice fuera de rango).
Aunque las colecciones permiten el uso de índices, no es necesario indicarlos siempre.
Por ejemplo, en una colección del tipo ArrayList, cuando hay que añadir el elemento
"Amapola" , se puede hacer simplemente flores.add("Amapola") . Al no especificar índice, el

elemento "Amapola" se añadiría justo al final de flores independientemente del tamaño y


del número de elementos que se hayan introducido ya.

Utilización de una ArrayList

import java.util.ArrayList;
import java.util.List;

public class Aplicacion {


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

// Añadir elementos
listaNombres.add("Antonio");
listaNombres.add("Susana");
listaNombres.add("Sara");
listaNombres.add("Sara");

// Iterar la lista
for (String unNombre : listaNombres) {
System.out.println(unNombre);

Programación 9 I.E.S. Luis Vélez de Guevara


Colecciones Colecciones

}
System.out.println();

// Borrar elementos
listaNombres.remove(0);
listaNombres.remove("Sara");

// Sustituir elementos
listaNombres.set(0, "Pepe");

// Borrar según un criterio


listaNombres.removeIf(nombre -> nombre.contains("S"));

Tema 9 - Colecciones
// Otra forma de iterar la lista
for (int i = 0; i < listaNombres.size(); i++) {
System.out.println(listaNombres.get(i));
}
System.out.println();
}
}

2.3 Colecciones sin elementos repetidos (Set)


Interfaz Set

▪ No puede contener repetidos.


▪ Propone tres implementaciones: HashSet, TreeSet y LinkedHastSet.
▪ HashSet es la más eficiente, pero no nos asegura nada sobre el orden.
▪ TreeSet utiliza un árbol Red-Black, ordena según el valor.
▪ LinkedHashSet es un HashSet ordenado por orden de inserción.

Operaciones con un Set

Algunas de las operaciones más frecuentes son:

▪ Set.of(elemento1, elemento2...): Método estático que permite crear un


conjunto inmutable con entre 0 y 10 elementos.
▪ add(elmento): Añade un elemento al conjunto, si aun no está contenido.
▪ addAll(coleccion): Añade todos los elementos de la colección pasada como
argumento si es que aun no están presentes.
▪ remove(elemento): Elimina un elemento del conjunto.
▪ contains(elemento): Comprueba si un elemento está o no en el conjunto.
▪ isEmpty(): Verifica si el conjunto está vacío.
▪ clear(): Elimina todos los elementos del conjunto.

Programación 10 I.E.S. Luis Vélez de Guevara


Colecciones Colecciones

▪ size(): Devuelve el número de elementos de la lista.


▪ toArray(): Devuelve la lista como un array.

Utilización de un Set

import java.util.HashSet;
import java.util.Set;

public class Aplicacion {


public static void main(String[] args) {
Set<Integer> conjuntoTelefonos = new HashSet<>();

Tema 9 - Colecciones
// Añadir elementos
conjuntoTelefonos.add(600100100);
conjuntoTelefonos.add(600200200);
conjuntoTelefonos.add(600300300);
conjuntoTelefonos.add(600300300);

// Eliminar elementos
conjuntoTelefonos.remove(600200200);

// Comprobar si contiene un elemento


if (conjuntoTelefonos.contains(600100100)) {
System.out.println("El teléfono 600100100 pertenece al conjunto");
}
else {
System.out.println("El teléfono 600100100 no pertenece al conjunto");
}

// Iterar un conjunto
for (Integer unTelefono : conjuntoTelefonos) {
System.out.println(unTelefono);
}
System.out.println();

// Otra forma de crear un conjunto


Set<Integer> masTelefonos = Set.of(600100100, 700100100, 700200200);

// Añadir a un conjunto elementos de otro


conjuntoTelefonos.addAll(masTelefonos);

// Volver a iterar el conjunto


for (Integer unTelefono : conjuntoTelefonos) {
System.out.println(unTelefono);
}
System.out.println();
}
}

2.4 Colecciones clave-valor (Map)


Interfaz Map

▪ No es un subtipo de Collection (List y Set sí que lo son).

Programación 11 I.E.S. Luis Vélez de Guevara


Colecciones Colecciones

▪ Cada elemento tiene estructura clave-valor.


▪ La clave sirve para acceder directamente al valor.
▪ Las implementaciones son HashMap, TreeMap y LinkedHashMap. Las
consideraciones son análogas a Set.

Operaciones con un Map

Algunas de las operaciones más frecuentes son:

Tema 9 - Colecciones
▪ Map.of(clave1, valor1, clave2, valor2...): Método estático que permite crear un
diccionario inmutable con entre 0 y 10 entradas.
▪ get(clave): Devuelve el valor asociado a una clave.
▪ put(clave, valor): Permite insertar una pareja clave-valor.
▪ remove(clave): Elimina un elemento del conjunto.
▪ remove(clave, valor): Elimina un elemento del conjunto únicamente en caso de
que el valor asignado a la clave sea el indicado.
▪ containsKey(clave): Comprueba si una clave está presente en el diccionario.
▪ containsValue(valor): Comprueba si un valor está presente en el diccionario.
▪ isEmpty(): Verifica si el conjunto está vacío.
▪ clear(): Elimina todos los elementos del diccionario.
▪ size(): Devuelve el número de elementos de la lista.
▪ values(): Devuelve un Collection con los valores.
▪ keySet(): Devuelve un Set con todas las claves.
▪ entrySet(): Devuelve un Set con todos los pares (clave, valor).

Implementaciones de Map

Con cualquier Map podemos estructurar datos con forma de diccionario. Esta estructura
contiene una serie de elementos (que son las entradas) que a su vez están formadas por
un par (clave, valor). La clave (key) permite acceder al valor. No puede haber claves
duplicadas.

Existen varias implementaciones de esta interfaz: HashMap, TreeMap y


LinkedHashMap. Nosotros estudiaremos la primera.

Utilización de un Map

import java.util.HashMap;
import java.util.Map;

Programación 12 I.E.S. Luis Vélez de Guevara


Colecciones Colecciones

public class Aplicacion {


public static void main(String[] args) {
Map<String, Integer> agendaTelefonica = new HashMap<>();

// Añadir entradas al diccionario


agendaTelefonica.put("Antonio", 600100100);
agendaTelefonica.put("Susana", 600200200);
agendaTelefonica.put("Sara", 600300300);
agendaTelefonica.put("Sara", 600400400);

// Iterar el diccionario
for (String clave : agendaTelefonica.keySet()) {
int valor;

Tema 9 - Colecciones
valor = agendaTelefonica.get(clave);
System.out.printf("El teléfono de %s es: %d\n", clave, valor);
}
System.out.println();

// Modificar entradas
agendaTelefonica.put("Antonio", 600777888);

// Comprobar si existe una clave


if (agendaTelefonica.containsKey("Susana")) {
System.out.printf("Tenemos el teléfono de Susana: %d\n",
agendaTelefonica.get("Susana"));
}
else {
System.out.println("No tenemos el teléfono de Susana");
}

// Comprobar si existe un valor


if (agendaTelefonica.containsValue(600777888)) {
System.out.println("Existe alguien con el teléfono 600777888");
}
else {
System.out.println("No existe nadie con el teléfono 600777888");
}

// Otra forma de iterar el diccionario


for (Map.Entry entrada : agendaTelefonica.entrySet()) {
System.out.printf("El teléfono de %s es: %d\n", entrada.getKey(),
entrada.getValue());
}
System.out.println();

// Listar todas las claves


for (String unaClave : agendaTelefonica.keySet()) {
System.out.println(unaClave);
}
System.out.println();

// Listar todos los valores


for (int unValor : agendaTelefonica.values()) {
System.out.println(unValor);
}
System.out.println();
}
}

Programación 13 I.E.S. Luis Vélez de Guevara


Colecciones Iteradores

3 Iteradores
Son clases auxiliares que implementan la interfaz Iterator. Nos permiten recorrer los
elementos de una colección. Con un iterador podemos recuperar fácilmente los elementos
y realizar operaciones con cada uno de ellos.

Iterator es un iterador universal, ya que se puede aplicar a cualquier objeto de tipo


colección. No permite recorrer la colección hacia adelante. En cambio, ListIterator que
extiende a Iterator, nos permite ir en ambos sentidos. Tanto las operaciones de lectura

Tema 9 - Colecciones
como las de borrado están permitidas.

3.1 Métodos de un iterador


▪ hasNext(): Devuelve true mientras queden elementos de la colección por recorrer.
▪ next(): Devuelve el siguiente elemento de la colección. Si no hay más, lanza una
NoSuchElementException.
▪ remove(): Borra el último elemento iterado. Si la lista es modificada mientras está
siendo iterada, lanza una ConcurrentModificationException.
▪ forEachRemaining(accion): Realiza la acción indicada con los elementos
restantes (los no iterados).

3.2 Utilización de iteradores

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Aplicacion {


public static void main(String[] args) {
// Crear una lista de enteros
List<Integer> listaNumeros = new ArrayList<>();

// Añadir elementos a la lista


listaNumeros.add(12);
listaNumeros.add(10);
listaNumeros.add(8);
listaNumeros.add(6);

// Obtener un objeto iterador para la lista


Iterator<Integer> it = listaNumeros.iterator();

// Mientras haya un elemento más a iterar


while (it.hasNext()) {
// Leer el siguiente elemento
Integer unNumero = it.next();

if (unNumero < 10) {


// Eliminar el elemento actual
it.remove();
}
}

Programación 14 I.E.S. Luis Vélez de Guevara


Colecciones Iteradores

// Imprimir la lista
System.out.println(listaNumeros);
}
}

Tema 9 - Colecciones

Programación 15 I.E.S. Luis Vélez de Guevara


Colecciones Localización e identificación de objetos

4 Localización e identificación de
objetos
4.1 Los métodos equals() y hashCode()
Son dos métodos que están presentes en la clase Object, de modo que cualquier otra
clase siempre va a disponer, al menos, de la implementación por defecto de los mismos.
Cuando trabajamos con colecciones, nos interesa que nuestras clases realicen su propia

Tema 9 - Colecciones
implementación de este métodos, dado que son necesarios para el correcto
funcionamiento de ciertas operaciones.

Para explicar estos métodos, tomaremos como ejemplo la siguiente clase Persona:

public class Persona {


private String nombre;
private String dni;
private int edad;

public Persona(String nombre, String dni, int edad) {


super();
this.nombre = nombre;
this.dni = dni;
this.edad = edad;
}
}

Método equals()

Permite conocer si un objeto es igual a otro. Es útil, por ejemplo, cuando buscamos
elementos en una lista o dentro de un conjunto.

Según la documentación oficial el método equals() debe cumplir el siguiente contrato


para que podamos decir que está bien implementado:

▪ Reflexivo: Para cualquier referencia no nula de un valor x , x.equals(x) debe


regresar true .
▪ Simétrico: Para cualquier referencia no nula de un valor x y un valor y ,
x.equals(y) debe regresar lo mismo que y.equals(x) .
▪ Transitivo: Para un valor no nulo de x , y y z se debe cumplir que si x.equals(y)

y y.equals(z) son ciertos, entonces x.equals(z) es cierto.


▪ Consistente: Se puede invocar equals() tantas veces consecutivas como se quiera
y deberá resolver siempre el mismo valor a menos que una de sus partes cambie.
▪ Para cualquier valor no nulo de x , x.equals(null) debe resolver a false .

Programación 16 I.E.S. Luis Vélez de Guevara


Colecciones Localización e identificación de objetos

Una implementación para Persona adecuada sería la siguiente:

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;

if (obj == null)
return false;

if (getClass() != obj.getClass())
return false;

Tema 9 - Colecciones
Persona other = (Persona) obj;

return Objects.equals(dni, other.dni)


&& edad == other.edad
&& Objects.equals(nombre, other.nombre);
}

Método hashCode()

Este método devuelve un número entero que sirve como resumen o huella
característica de un objeto. Esto permite comparar o localizar objetos de forma rápida en
una estructura. El valor hash debe ser calculado en consistencia con la definición de
igualdad de la clase, por lo tanto, no podemos hablar de sobrescribir el método equals()
si no sobrescribimos también el método hashCode(). Esto se debe a que, cuando dos
objetos tienen el mismo hashCode(), es necesario utilizar equals() para comprobar si
se trata del mismo objeto.

El contrato de hashCode() es mas simple que el de equals():

▪ Consistencia interna: El valor de hashCode() debe cambiar solo si una


propiedad de las que afecta equals() cambia.
▪ Consistencia de igualdad: Objetos que son iguales deben devolver el mismo
hashCode.
▪ Colisiones: Objetos que no son iguales podrían devolver el mismo hashCode.

Una implementación para Persona adecuada sería la siguiente:

@Override
public int hashCode() {
return Objects.hash(dni, edad, nombre);
}

Si dejáramos el comportamiento por defecto, entonces algunas características de algunas


clases dejarían de funcionar correctamente. Tal es el caso del método get(clave) de la
clase HashMap, la cual utiliza el hashCode para comparar la clave indicada entre todas
las que pertenecen al diccionario.

Programación 17 I.E.S. Luis Vélez de Guevara


Colecciones Localización e identificación de objetos

Por lo tanto, la implementación de la clase Persona, quedaría así:

import java.util.Objects;

public class Persona {


private String nombre;
private String dni;
private int edad;

public Persona(String nombre, String dni, int edad) {


super();
this.nombre = nombre;
this.dni = dni;

Tema 9 - Colecciones
this.edad = edad;
}

@Override
public String toString() {
return "Persona [nombre=" + nombre + ", dni=" + dni + ", edad=" + edad + "]";
}

@Override
public int hashCode() {
return Objects.hash(dni, edad, nombre);
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;

if (obj == null)
return false;

if (getClass() != obj.getClass())
return false;

Persona other = (Persona) obj;

return Objects.equals(dni, other.dni)


&& edad == other.edad
&& Objects.equals(nombre, other.nombre);
}
}

4.2 Influencia de equals() y hashCode() en una


colección
El el siguiente ejemplo se usa una ArrayList para almacenar objetos de la clase
Persona. Obsérvese que operaciones, como por ejemplo la de borrado, solo funcionan
como se espera si se ha implementado el método equals().

import java.util.ArrayList;
import java.util.List;

public class Aplicacion {


public static void main(String[] args) {
// Crear una lista de objetos
List<Persona> listaPersonas = new ArrayList<>();

Programación 18 I.E.S. Luis Vélez de Guevara


Colecciones Localización e identificación de objetos

// Añadir elementos a la lista


listaPersonas.add(new Persona("Alberto", "10001000A", 33));
listaPersonas.add(new Persona("Silvia", "20002000B", 34));
listaPersonas.add(new Persona("Maria", "30003000C", 22));

// Borrar una persona


// NOTA: Solo funcionará correctamente si se ha implementado equals()
listaPersonas.remove(new Persona("Maria", "30003000C", 22));

// Iterar la lista
for (Persona unaPersona : listaPersonas) {
System.out.println(unaPersona);
}
}
}

Tema 9 - Colecciones
La fórmula utilizada para calcular hashCode() influirá en la eficiencia a la hora de
localizar objetos dentro de colecciones basadas en tablas Hash, como por ejemplo un
HashSet. Cuanto mejor sea la implementación de hashCode(), menos colisiones habrá
y, por lo tanto, mejor será la eficiencia de estas estructuras de datos.

Programación 19 I.E.S. Luis Vélez de Guevara


Colecciones Interfaces Comparable y Comparator

5 Interfaces Comparable y Comparator


Muchas operaciones entre objetos nos obligan a compararlos, por ejemplo, al buscar,
ordenar, etc. Los tipos primitivos y algunas clases ya implementan su orden, que puede
ser numérico, lexicográfico o de otro tipo. Para nuestras clases, tendremos que especificar
el orden con el que las vamos a tratar.

5.1 Comparable

Tema 9 - Colecciones
Se trata de un interfaz sencillo:

public interface Compararable<T> {


public int compareTo(T objeto);
}

▪ Recibe un objeto del mismo tipo.


▪ Devuelve 0 si son iguales, un valor negativo si es menor, y uno positivo si es
mayor.
▪ Nos sirve para indicar el orden principal de una clase.

5.2 Comparator
Se trata de un interfaz sencillo:

public interface Comparator<T> {


public int compare(T objeto1, T objeto2);
}

▪ Recibe dos argumentos.


▪ Devuelve 0 si son iguales, un valor negativo si es menor el primero, y uno
positivo si es mayor.
▪ Nos sirve para indicar un orden puntual, diferente al orden principal de una
clase.

5.3 Ordenar una lista


Los elementos de una lista se pueden ordenar con el método sort(). La sintaxis es
Collections.sort(lista) para ordenar ascendentemente o Collections.reverse(lista) para

ordenar descendentemente. Para ello, la clase contenida en la lista debe implementar la


interfaz Compararable. Por ejemplo, para poder ordenar una lista de personas, la clase
Persona debe implementar Compararable:

Programación 20 I.E.S. Luis Vélez de Guevara


Colecciones Interfaces Comparable y Comparator

public class Persona implements Comparable<Persona> {


private String nombre;
private String dni;
private int edad;

// ...

@Override
public int compareTo(Persona otraPersona) {
return this.nombre.compareTo(otraPersona.nombre);
}
}

Tema 9 - Colecciones
En este caso, hemos utilizado el nombre como criterio para implementar
compareTo(), por lo que la lista se ordenará alfabéticamente según el nombre de las
personas. Este será el criterio de ordenación por defecto. Por ejemplo:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Aplicacion {


public static void main(String[] args) {
// Crear una lista de objetos
List<Persona> listaPersonas = new ArrayList<>();

// Añadir elementos a la lista


listaPersonas.add(new Persona("Alberto", "10001000A", 33));
listaPersonas.add(new Persona("Silvia", "20002000B", 34));
listaPersonas.add(new Persona("Maria", "30003000C", 22));

// Ordenar la lista
Collections.sort(listaPersonas);

// Iterar la lista
for (Persona unaPersona : listaPersonas) {
System.out.println(unaPersona);
}
}
}

Producirá la salida:

Persona [nombre=Alberto, dni=10001000A, edad=33]


Persona [nombre=Maria, dni=30003000C, edad=22]
Persona [nombre=Silvia, dni=20002000B, edad=34]

Si queremos utilizar otros criterios diferentes para ordenar la lista, tendremos que
implementar la interfaz Comparator. Esto se suele hace creado una clase auxiliar que
será la que lo implemente. Aunque no es estrictamente necesario, suele ser buena idea
que esta clase esté anidada. Nuestra clase Persona, al completo, quedaría así:

import java.util.Comparator;
import java.util.Objects;

public class Persona implements Comparable<Persona> {


private String nombre;

Programación 21 I.E.S. Luis Vélez de Guevara


Colecciones Interfaces Comparable y Comparator

private String dni;


private int edad;

// Clase anidada que implementa Comparator<Persona>


public static class ComparadorEdad implements Comparator<Persona> {
@Override
public int compare(Persona p1, Persona p2) {
return Integer.compare(p1.edad, p2.edad);
}
}

// Constructor y resto de métodos...


}

Tema 9 - Colecciones
Para ordenar por edad, haríamos lo siguiente:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Aplicación {


public static void main(String[] args) {
// Crear una lista de objetos
List<Persona> listaPersonas = new ArrayList<>();

// Añadir elementos a la lista


listaPersonas.add(new Persona("Alberto", "10001000A", 33));
listaPersonas.add(new Persona("Silvia", "20002000B", 34));
listaPersonas.add(new Persona("Maria", "30003000C", 22));

// Ordenar la lista
Collections.sort(listaPersonas, new Persona.ComparadorEdad());

// Iterar la lista
for (Persona unaPersona : listaPersonas) {
System.out.println(unaPersona);
}
}
}

El resultado sería el siguiente:

Persona [nombre=Maria, dni=30003000C, edad=22]


Persona [nombre=Alberto, dni=10001000A, edad=33]
Persona [nombre=Silvia, dni=20002000B, edad=34]

Si quisiéramos que el orden fuera en sentido inverso, tendríamos que utilizar


Collections.reverseOrder(comparador) que invierte el sentido del comparador indicado. Por

ejemplo:

Collections.sort(listaPersonas,
Collections.reverseOrder(new Persona.ComparadorEdad()));

Programación 22 I.E.S. Luis Vélez de Guevara


Colecciones Interfaces Comparable y Comparator

Tema 9 - Colecciones
Cuadro de resumen sobre lo métodos relacionados con la búsqueda y la ordenación

Programación 23 I.E.S. Luis Vélez de Guevara


Colecciones Anexo - Clase Persona

6 Anexo - Clase Persona


import java.util.Comparator;
import java.util.Objects;

public class Persona implements Comparable<Persona> {


// Propiedades de instancia
private String nombre;
private String dni;
private int edad;

// Comparación alternativa por edad

Tema 9 - Colecciones
public static class ComparadorEdad implements Comparator<Persona> {
@Override
public int compare(Persona p1, Persona p2) {
return Integer.compare(p1.edad, p2.edad);
}
}

// Constructor
public Persona(String nombre, String dni, int edad) {
super();
this.nombre = nombre;
this.dni = dni;
this.edad = edad;
}

// toString
@Override
public String toString() {
return "Persona [nombre=" + nombre + ", dni=" + dni + ", edad=" + edad + "]";
}

// hashCode
@Override
public int hashCode() {
return Objects.hash(dni, edad, nombre);
}

// equals
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;

Persona other = (Persona) obj;

return Objects.equals(dni, other.dni)


&& edad == other.edad
&& Objects.equals(nombre, other.nombre);
}

// Orden natural (por defecto)


@Override
public int compareTo(Persona otraPersona) {
return this.nombre.compareTo(otraPersona.nombre);
}
}

Programación 24 I.E.S. Luis Vélez de Guevara


Colecciones Referencias

7 Referencias
▪ Colecciones explicadas con animaciones
▪ Collections Framework Overview
▪ Tutorial: Collections

Tema 9 - Colecciones

Programación 25 I.E.S. Luis Vélez de Guevara

También podría gustarte