Está en la página 1de 24

Estructuras de Datos

Ingeniería Informática en Sistemas de Información


Enseñanza Básica
TEMA 1: Introducción al Java Collections
Framework

CONTENIDO

1 INTRODUCCIÓN.............................................................................................................................................................2
1.1. ELEMENTOS DEL JCF..................................................................................................................................................2
2 INTERFAZ COLLECTION............................................................................................................................................3
3 ITERADORES...................................................................................................................................................................7
3.1. INTERFAZ ITERATOR...................................................................................................................................................7
3.2. INTERFAZ LISTITERATOR..........................................................................................................................................10
4 INTERFACES COMPARABLE Y COMPARATOR.................................................................................................16
4.1. INTERFAZ COMPARABLE...........................................................................................................................................16
4.2. INTERFAZ COMPARATOR..........................................................................................................................................19
4.3. ¿CUÁNDO USAR COMPARABLE Y COMPARATOR?....................................................................................................23
5 UTILIDADES PARA OBJETOS CONTENEDORES: CLASE JAVA.UTIL.COLLECTIONS...........................23
5.1. ORDENACIÓN............................................................................................................................................................24
5.2. INVERSIÓN DEL ORDEN.............................................................................................................................................25
5.3. BÚSQUEDA................................................................................................................................................................25
5.4. COPIAR LISTA...........................................................................................................................................................25
5.5. RELLENAR UNA LISTA..............................................................................................................................................26
5.6. MÁXIMOS Y MÍNIMOS...............................................................................................................................................27
5.7. CONSTANTES.............................................................................................................................................................27
6 CLASE ARRAYS (AMPLIACIÓN)..............................................................................................................................28
6.1. TRATAR MATRIZ COMO LISTA..................................................................................................................................28
6.2. MÉTODOS SIMILARES A LOS DE COLLECTIONS.........................................................................................................28
7 CLASE JAVA.LANG.MATH........................................................................................................................................28
8 BIBLIOGRAFÍA.............................................................................................................................................................30

Estructuras de Datos Página 1 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

1 Introducción
En la versión 1.2 del JDK se introdujo el Java Collections Framework o “estructura de colecciones
de Java” (en adelante JCF). Se trata de un conjunto de clases e interfaces que mejoran
notablemente las capacidades del lenguaje respecto a estructuras de datos. Además,
constituyen un excelente ejemplo de aplicación de los conceptos propios de la programación
orientada a objetos.

1.1. Elementos del JCF

Jerarquía de Interfaces del JCF

Interfaces de la JCF: Constituyen el elemento central de la JCF.


 Collection: define métodos para tratar una colección genérica de elementos
 Set: colección que no admite elementos repetidos
 SortedSet: set cuyos elementos se mantienen ordenados según el criterio establecido
 List: admite elementos repetidos y mantiene un orden inicial
 Map: conjunto de pares clave/valor, sin repetición de claves
 SortedMap: map cuyos elementos se mantienen ordenados según el criterio
establecido

Interfaces de soporte:
 Iterator: sustituye a la interfaz Enumeration. Dispone de métodos para recorrer una
colección y para borrar elementos.
 ListIterator: deriva de Iterator y permite recorrer lists en ambos sentidos.
 Comparable: declara el método compareTo() que permite ordenar las distintas
colecciones según un orden natural (String, Date, Integer, Double, …).
 Comparator: declara el método compare() y se utiliza en lugar de Comparable
cuando se desea ordenar objetos no estándar o sustituir a dicha interfaz.

Clases de propósito general: Son las implementaciones de las interfaces de la JFC.


 HashSet: Interfaz Set implementada mediante una hash table.
 TreeSet: Interfaz SortedSet implementada mediante un árbol binario ordenado.
 ArrayList: Interfaz List implementada mediante un array.
 LinkedList: Interfaz List implementada mediante una lista vinculada.
 HashMap: Interfaz Map implementada mediante una hash table.

Estructuras de Datos Página 2 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

 TreeMap: Interfaz SortedMap implementada mediante un árbol binario

Clases históricas: Son las clases Vector y Hashtable presentes desde las primeras versiones
de Java. En las versiones actuales, implementan respectivamente las interfaces List y Map,
aunque conservan también los métodos anteriores.

Algoritmos: La clase Collections dispone de métodos static para ordenar, desordenar,


invertir orden, realizar búsquedas, llenar, copiar, hallar el mínimo y hallar el máximo.

Clase Arrays: Es una clase de utilidad introducida en el JDK 1.2 que contiene métodos static
para ordenar, llenar, realizar búsquedas y comparar los arrays clásicos del lenguaje. Permite
también ver los arrays como lists.

2 Interfaz Collection
La interfaz Collection es implementada por los conjuntos (sets) y las listas (lists). Esta
interfaz, declarada en el paquete java.util, declara una serie de métodos generales utilizables
con Set y List.

public interfaz java.util.Collection


{
public boolean add(Object); // opcional
public boolean addAll(Collection); // opcional
public void clear(); // opcional
public boolean contains(Object);
public boolean containsAll(Collection);
public boolean equals(Object);
public int hashCode();
public boolean isEmpty();
public Iterator iterator();
public boolean remove(Object); // opcional
public boolean removeAll(Collection); // opcional
public boolean retainAll(Collection); // opcional
public int size();
public Object[] toArray();
public Object[] toArray(Object[]);
}

Los métodos indicados como “// opcional” pueden no estar disponibles en algunas
implementaciones, como por ejemplo en las clases que no permiten modificar sus objetos. Por
supuesto dichos métodos deben ser definidos, pero lo que hacen al ser llamados es lanzar una
UnsupportedOperationException.

Métodos para agregar y eliminar elementos


 boolean add(Object element). Añade un elemento a la colección, devolviendo true si fue
posible añadirlo y false en caso contrario (por ejemplo, un set que ya contenga el
elemento).
 boolean remove(Object element). Elimina un único elemento (si lo encuentra), y
devuelve true si la colección ha sido modificada.

Métodos para realizar consultas


 int size(). Devuelve el número de elementos disponibles.
 boolean isEmpty(). Devuelve true si la colección es vacía.

Estructuras de Datos Página 3 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

 boolean contains(Object element). Devuelve true si el elemento pertenece a la


colección.

Métodos para recorrer todos los elementos


 Iterator iterator(). Devuelve una referencia Iterator que permite recorrer una colección
con los métodos next() y hasNext(). Permite también borrar el elemento actual con
remove().

Métodos para realizar varias operaciones simultáneamente


 boolean containsAll(Collection collection). Igual que contains(), pero con un conjunto de
elementos.
 boolean addAll(Collection collection). Igual a add(), pero añade un conjunto de datos si
es posible.
 void clear(). Elimina todos los elementos.
 void removeAll(Collection collection). Igual que remove(), pero elimina el conjunto de
elementos que se pasa como parámetro.
 void retainAll(Collection collection). Elimina todos los elementos menos los
especificados por la colección pasada como parámetro.

Otros Métodos
 boolean equals(Object). Implementa la igualdad o equivalencia. Retorna true si el objeto
que llama al método es equivalente al que se pasa como parámetro. Devuelve false si el
argumento es nulo.
 int hashCode(). A la hora de acceder, añadir, o eliminar un objeto contenido en un
hashtable, la implementación de dicha estructura invocará este método sobre el objeto
para obtener un int que pueda ser utilizado en la elaboración del índice en el hashtable.
Durante la ejecución de un programa este método ha de retornar el mismo int siempre
que sea invocado sobre el mismo objeto. Siempre y cuando sea factible ha de ser único
para cada objeto. Por ello, aunque esta implementación no es requerida, el método
devuelve la dirección física del objeto en memoria.
 Object[] toArray(). Permiten convertir una colección en un array.

Un aspecto importante es que las colecciones sólo pueden contener objetos. Por ello, en
versiones anteriores, Java no permitía que a una colección se pudieran añadir elementos que no
fueran objetos, es decir, de tipos básicos o primitivos, es decir, que una instrucción como
c.add(20) era incorrecta, y se tenía que sustituir por c.add(new Integer(20)), en la que se usa la
envoltura Integer. A partir de la versión Java 5 fueron integrados los mecanismos de auto-
boxing y auto-unboxing para permitir la conversión de valores primitivos hacia sus
respectivos objetos (envolturas) de manera directa y sin mayores complicaciones. Es decir, que
ya sí se permiten instrucciones del tipo c.add(20).

Ejemplo:

import java.util.*; // Para usar los elementos del JCF


public class Ppal {
public static void main(String[] args) {
int i;

// Colección c1

Collection c1 = new ArrayList();


c1.add(10); // Es equivalente a c1.add(new Integer(10));
c1.add(20);
c1.add(30);

Estructuras de Datos Página 4 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

c1.add(40);
c1.add(50);
c1.add(60);

// Colección c2 – como una lista

List c2 = new ArrayList();


for (i=1; i<=6; i++)
c2.add(new Integer(i*10)); // Es equivalente a c2.add(i*10);

// Recorrido de colecciones como tablas – NO ES LO RECOMENDADO

System.out.println("La colección 1 tiene " + c1.size() + " elementos");


Object [] t = c1.toArray();
for (i=0; i<t.length; i++)
System.out.println("Elem " + i + ": " + (Integer)t[i]);

System.out.println("La colección 2 tiene " + c2.size() + " elementos");


Object [] t2 = c2.toArray();
for (i=0; i<t2.length; i++)
System.out.println("Elem " + i + ": " + (Integer)t2[i]);

c2.remove(new Integer(20));

// Comparación de colecciones

if (c1.equals(c2))
System.out.println("Son iguales");
else
System.out.println("Son distintas");

if (c1.containsAll(c2))
System.out.println("c2 contenida en c1");
else
System.out.println("c2 no contenida en c1");
}
}

NOTA: Aunque la interfaz Collection se puede usar para instanciar objetos, su principal
cometido es definir los métodos comunes a todas las colecciones. Por ello, lo normal es usar
algunas de sus interfaces hijas (List, Set o SortedSet). Así pues, a partir de ahora usaremos el
interfaz List como ejemplo de colección, ya que es más apropiado.

Estructuras de Datos Página 5 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

3 Iteradores
Los objetos de tipo iterador permiten recorrer colecciones. Disponen de un conjunto de métodos
que permiten avanzar sobre la colección y obtener los objetos de ésta durante un recorrido para
su tratamiento. Existen dos interfaces declarados en el JCF: java.util.Iterator, que dispone de
métodos para recorrer una colección y para borrar elementos; y java.util.ListIterator, que
permite recorrer una lista en ambos sentidos, siendo éste segundo descendiente del primero.

3.1. Interfaz Iterator

El interfaz Iterator sustituye a Enumeration, utilizada en versiones anteriores (JDK 1.1).


Podemos ver un iterador como un “puntero” que señala un elemento de una colección, que
denominamos elemento actual, y es capaz de pasar al siguiente elemento para así recorrer
dicha colección.

El interfaz Iterator proporciona sólo tres métodos:

public interfaz java.util.Iterator


{
public boolean hasNext();
public Object next();
public void remove(); //opcional
}

 hasNext(): devuelve cierto si el elemento actual tiene siguiente en la colección, es


decir, mientras existan elementos no tratados mediante el método next.

 next(): devuelve una referencia al siguiente elemento en la colección, es decir, coloca el


iterador en el elemento siguiente y lo devuelve (como Object). Es el método utilizado
para acceder a los elementos de una colección. Lanza NoSuchElementException si se
invoca un número de veces superior al número de elementos existentes en la colección.

 remove(): Elimina de la colección el último elemento retornado por next. Solo puede ser
llamado una vez por cada llamada a next, y siempre después de éste. Es la única forma
segura de eliminar un elemento mientras se está recorriendo una colección. Eleva
IllegalEstateException si no se cumplen las condiciones expuestas para la llamada; y
UnsupportedOperationException si la implementación de este interfaz no incluyó este
método (ya que es opcional).

Como vimos en apartados anteriores, la interfaz Collection dispone de un método denominado


iterator(), que devuelve un Iterator situado antes del primer elemento de la colección, (es
decir, si it es un iterador, it.next() devolverá el primer elemento). El método iterator() es
utilizado para inicializar los iteradores antes de comenzar el recorrido de la colección. Así, el
recorrido básico de una colección es el siguiente:

Iterator it = colección.iterator();
while (it.hasNext())
{
Tipo obj = (<Casting>)it.next();
TRATAR obj
}

Estructuras de Datos Página 6 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

Para los siguientes ejemplos, usaremos la clase Persona y la interfaz Empleado, definidos de la
siguiente forma:

public interface Empleado{


public String getNombre();
public String getApellidos();
public int getEdad();
}

public class Persona implements Comparable, Empleado{


private String nombre, apellidos;
private int edad;
public Persona(String n, String a, int e){ ... }
< Aquí irían el resto de métodos >
}

Ejemplo: Recorrido de una colección de Personas.

public class TestIterator{


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

// Inicializa la lista c

c.add(new Persona("Pepe", "Lopez Perez", 25));


c.add(new Persona("Lola", "Lopez Aguilar", 23));
c.add(new Persona("Pepe", "Lopez Perez", 21));
c.add(new Persona("Antonio", "Lopez Perez", 25));
c.add(new Persona("Alicia", "Sanchez Olmo", 21));

// Recorrido: Imprime la lista elemento a elemento


Iterator it = c.iterator();
while(it.hasNext())
System.out.println((Persona)it.next());

// Recorrido: Incrementa en 1 la edad de todas las personas


System.out.println("Incrementar en 1 la edad de todas las personas------");
it=c.iterator();
while(it.hasNext())
{
Persona p = (Persona) it.next();
p.setEdad(p.getEdad()+1);
}

// Recorrido: Vuelve a imprimir la lista elemento a elemento


it = c.iterator();
while(it.hasNext())
System.out.println((Persona)it.next());
}
}

La salida de este programa es:


Lopez Perez, Pepe (25)
Lopez Aguilar, Lola (23)
Lopez Perez, Pepe (21)
Lopez Perez, Antonio (25)
Sanchez Olmo, Alicia (21)
Incrementar en 1 la edad de todas las personas------
Lopez Perez, Pepe (26)
Lopez Aguilar, Lola (24)
Lopez Perez, Pepe (22)

Estructuras de Datos Página 7 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

Lopez Perez, Antonio (26)


Sanchez Olmo, Alicia (22)
Process Exit...

Ejemplo: Eliminar elementos de una colección de Empleados. Este ejemplo es realizado usando
la interfaz Empleado en vez de la clase Persona para rellenar la colección. En este caso,
pretendemos borrar todos los empleados de la colección cuya edad sea superior a 24 años.

public class TestIterator2{


public static void main(String args[]){

List c = new ArrayList();

// Inicializa la lista c
Empleado e1 = new Persona("Pepe", "Lopez Perez", 25);
Empleado e2 = new Persona("Lola", "Lopez Aguilar", 23);
Empleado e3 = new Persona("Pepe", "Lopez Perez", 21);
Empleado e4 = new Persona("Antonio", "lopez Perez", 25);
Empleado e5 = new Persona("Alicia", "Sanchez Olmo", 21);
c.add(e1); c.add(e2); c.add(e3); c.add(e4); c.add(e5);
// Recorrido: Imprime la lista elemento a elemento
Iterator it = c.iterator();
while(it.hasNext())
System.out.println((Empleado)it.next());

// Recorrido: Elimina los mayores de 24 años


System.out.println("Quitar los Empleados mayores de 24 años------");
it=c.iterator();
while(it.hasNext())
{
Empleado e = (Empleado) it.next();
if(e.getEdad()>24)
it.remove();
}
// Recorrido: Vuelve a imprimir la lista elemento a elemento
it = c.iterator();
while(it.hasNext())
System.out.println((Persona)it.next());

}
}

La salida de este programa es:


Lopez Perez, Pepe (25)
Lopez Aguilar, Lola (23)
Lopez Perez, Pepe (21)
lopez Perez, Antonio (25)
Sanchez Olmo, Alicia (21)
Quitar los Empleados mayores de 24 años------
Lopez Aguilar, Lola (23)
Lopez Perez, Pepe (21)
Sanchez Olmo, Alicia (21)
Process Exit...

Estructuras de Datos Página 8 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

3.2. Interfaz ListIterator

Este tipo especial de iterador (deriva de la interfaz Iterator) sólo es válido para recorrer
listas (List), nunca Collection, Set o SortedSet. Añade métodos a Iterator para iterar hacia
atrás, para insertar o remplazar durante la iteración y para obtener la posición del puntero
interno.

Entre cada par de elementos, y también antes del primero y después del último existe una
posible posición del iterados. Los elementos se numeran desde 0 a n-1, pero los valores válidos
para el índice son de 0 a n. Puede suponerse que el índice i está en la frontera entre los
elementos i-1 e i. Por ejemplo:

(0) ele0 (1) ele1 (2) ele2 (3) ele3 (4)

El interfaz List incorpora dos métodos para asignar o inicializar un ListIterator, en concreto, el
método ListIterator() de una lista devuelve un ListIterator cuyo puntero es cero. El método
ListIterator(int) posiciona el puntero en el índice int.

Los métodos del interfaz ListIterator son los siguientes:

public interfaz ListIterator extends Iterator


{
public void add(Object);
public boolean hasNext();
public boolean hasPrevious();
public Object next();
public int nextIndex();
public Object previous();
public int previousIndex();
public void remove();
public void set(Object);
}
Como vemos, además de los métodos del interfaz padre Iterator, el interfaz ListIterator
implementa otros. La descripción de todos ellos es:

 hasNext(): devuelve un cierto si el elemento actual tiene siguiente en la colección, es


decir, devuelve verdadero mientras existan elementos no tratados mediante el método
next.

 hasPrevious(): devuelve un cierto si el elemento actual tiene anterior en la lista, es


decir, devuelve verdadero mientras existan elementos no tratados mediante el método
previous.

 next(): devuelve el elemento en cuyo índice se halla el puntero y avanza una posición el
valor del mismo. La primera vez que se invoca sobre el objeto retornado por el método
ListIterator() devuelve el primer elemento de la lista. Cuando se invoca sobre el objeto
retornado por ListIterator(int) devuelve el elemento de índice int. Si int fuera el tamaño
de la lista o si la iteración ha alcanzado el final de la lista, lanzaría la excepción
NoSuchElementException.

 previous(): devuelve el elemento situado inmediatamente antes de la posición actual


del iterador y resta uno a su valor (retrocede en la lista). Cuando es invocado sobre el
objeto devuelto por ListIterator() lanza NoSuchElementException. Si se llama sobre el

Estructuras de Datos Página 9 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

objeto devuelto por ListIterator(int) devuelve el objeto situado en el índice int-1. También
lanza NoSuchMethodException si la iteración ha alcanzado el principio de la lista.

 nextIndex(): devuelve el índice del elemento que sería retornado por la próxima
llamada a next(), es decir la posición actual del puntero. Si el puntero se encuentra al
final de la colección devuelve su tamaño.

 previousIndex(): devuelve el índice del elemento que sería retornado por la próxima
llamada a previous(), es decir la posición actual del puntero menos uno. Devuelve -1 si el
puntero se encuentra al comienzo de la lista.

 remove(): elimina de la lista el último elemento retornado por next() o previous(). Sólo
puede ser llamado una vez por cada llamada a next() o previous(), y sólo si no se invocó
add() o remove() después. Los índices de los elementos posteriores son decrementados
en uno. Lanza UnsupportedOperationException si la implementación de este interfaz no
incorporó este método; e IllegalStateException si next o previous no fueron llamados, o
bien se invocó add o remove tras la última llamada a next o previous.

 add(Object): inserta el objeto en la lista en la posición actual del puntero y aumenta en


uno su valor. La siguiente llamada a next() quedaría sin afectar, pero previous()
devolvería el elemento recién insertado. Los valores de los índices de elementos
posteriores son incrementados en uno. No es necesario haber invocado a next o
previous con anterioridad. Lanza las siguientes excepciones:
UnsupportedOperationException, si la implementación de este interfaz no incorporó este
método; ClassCastException, si el tipo de este objeto impidió su adición a una lista;
IllegalStateException, si este objeto infringe alguna restricción al ser añadido a una
Collection.

 set(Object) remplaza el último elemento producido por next o previous por el objeto
especificado. Puede ser invocado varias veces sin necesidad de llamar nuevamente a
next o previous, siempre y cuando no aparezcan add o remove entre dichas llamadas.
Lanza las siguientes excepciones: UnsupportedOperationException, si la
implementación de este interfaz no incorporó este método; ClassCastException, si el
tipo de este objeto impidió su adición a una lista, IllegalStateException, si este objeto
infringe alguna restricción que impida su adicción a la lista, o bien, next o previous no
fueron llamados, o lo fueron pero después de la invocación a add o remove.

El recorrido básico ascendente de una lista mediante un ListIterator es el idéntico al de Iterator,


mientras que el recorrido descendente es el siguiente:

ListIterator it = lista.listIterator(<posición de inicio>);


while (it.hasPrevious())
{
Tipo obj = (<Casting>)it.previous();
TRATAR obj
}

Estructuras de Datos Página 10 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

Ejemplo:

import java.util.*;
public class TestListIterator{
public static void main(String args[]){

List c = new ArrayList();


Empleado e1 = new Persona("Pepe", "Lopez Perez", 25);
Empleado e2 = new Persona("Lola", "Lopez Aguilar", 23);
Empleado e3 = new Persona("Pepe", "Lopez Perez", 21);
Empleado e4 = new Persona("Antonio", "lopez Perez", 25);
Empleado e5 = new Persona("Alicia", "Sanchez Olmo", 21);

c.add(e1); c.add(e2); c.add(e3); c.add(e4); c.add(e5);

//Recorrido hacia delante


System.out.println("----- Recorrido hacia delante: ");
ListIterator it = c.listIterator();
while(it.hasNext()) {
System.out.print("índice " + it.nextIndex() + ": ");
System.out.println((Empleado)it.next());
}

//Recorrido hacia atras


System.out.println("----- Recorrido hacia atrás: ");
it = c.listIterator(c.size());
while(it.hasPrevious()){
System.out.print("índice " + it.previousIndex() + ": ");
System.out.println((Empleado)it.previous());
}

//Recorrido hacia delante desde la posición 2


System.out.println("----- Recorrido hacia delante desde la posición 2 : ");
it = c.listIterator(2);
while(it.hasNext()){
System.out.print("índice " + it.nextIndex() + ": ");
System.out.println((Empleado)it.next());
}

//Recorrido hacia atrás desde la posición 2


System.out.println("----- Recorrido hacia atrás desde la posición 2 : ");
it = c.listIterator(2);
while(it.hasPrevious()){
System.out.print("índice " + it.previousIndex() + ": ");
System.out.println((Empleado)it.previous());
}

//Inserta un empleado en la posición 2 (tercer empledo)


System.out.println("----- Inserta un empleado en la posición 2
(tercer empleado): ");
Empleado eAux = new Persona("Teresa", "Gómez Gómez", 32);
it = c.listIterator(2);
it.add(eAux); // deja it apuntando al que acaba de insertar

//Modifica el empleado en la posición 1 (segundo empledo)


System.out.println("----- Modifica el empleado en la posición 1
(segundo empledo): ");
eAux = new Persona("DOLORES", "Lopez Aguilar", 40);
it = c.listIterator(1);
if(it.hasNext()) {
it.next();

Estructuras de Datos Página 11 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

it.set(eAux); //Modifica el último Objeto devuelto por next


}

//Recorrido hacia delante


System.out.println("----- Lista final: ");
it = c.listIterator();
while(it.hasNext()) {
System.out.print("índice " + it.nextIndex() + ": ");
System.out.println((Empleado)it.next());
}
}
}

La salida de este programa es:


----- Recorrido hacia delante:
índice 0: Lopez Perez, Pepe (25)
índice 1: Lopez Aguilar, Lola (23)
índice 2: Lopez Perez, Pepe (21)
índice 3: lopez Perez, Antonio (25)
índice 4: Sanchez Olmo, Alicia (21)
----- Recorrido hacia atrás:
índice 4: Sanchez Olmo, Alicia (21)
índice 3: lopez Perez, Antonio (25)
índice 2: Lopez Perez, Pepe (21)
índice 1: Lopez Aguilar, Lola (23)
índice 0: Lopez Perez, Pepe (25)
----- Recorrido hacia delante desde la posición 2 :
índice 2: Lopez Perez, Pepe (21)
índice 3: lopez Perez, Antonio (25)
índice 4: Sanchez Olmo, Alicia (21)
----- Recorrido hacia atrás desde la posición 2 :
índice 1: Lopez Aguilar, Lola (23)
índice 0: Lopez Perez, Pepe (25)
----- Inserta un empleado en la posición 2 (tercer empleado):
----- Modifica el empleado en la posición 1 (segundo empledo):
----- Lista final:
índice 0: Lopez Perez, Pepe (25)
índice 1: Lopez Aguilar, DOLORES (40)
índice 2: Gómez Gómez, Teresa (32)
índice 3: Lopez Perez, Pepe (21)
índice 4: lopez Perez, Antonio (25)
índice 5: Sanchez Olmo, Alicia (21)
BUILD SUCCESSFUL (total time: 0 seconds)

Estructuras de Datos Página 12 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

4 Interfaces Comparable y Comparator


Estas interfaces están orientadas a mantener ordenadas las colecciones (listas, sets y maps)
que deben mantener un orden. Para ello se dispone de las interfaces java.lang.Comparable y
java.util.Comparator (obsérvese que pertenecen a packages diferentes).

4.1. Interfaz Comparable

Se dice que las clases que implementan esta interfaz cuentan con un “orden natural”. Este
orden es total, es decir, que siempre han de poder ordenarse dos objetos cualesquiera del la
clase que implementa este interfaz. La interfaz Comparable declara el método compareTo() de
la siguiente forma:

public int compareTo(Object obj)

que compara su argumento implícito con el que se le pasa por ventana. Este método devuelve
un entero negativo, cero o positivo según el argumento implícito (this) sea anterior, igual o
posterior al objeto obj., respectivamente.

Si se redefine, el método compareTo() debe ser programado con cuidado: es muy conveniente
que sea coherente con el método equals() y que cumpla la propiedad transitiva.(Si X<Y y
Y<Z => X<Z)

Las listas y las tablas cuyos elementos implementan Comparable pueden ser ordenadas con los
métodos Collections.sort() y Arrays.sort(). Por ejemplo, si una clase implementa
Comparable, se puede utilizar en las siguientes acciones sin necesidad de un Comparator:

 Si ObjArray es una matriz, puede ser ordenada mediante Arrays.sort(ObjArray).


 Si ObjList es una Lista, puede ser ordenada mediante Collections.sort(ObjList), o se
puede buscar un objeto obj mediante Collections.binarySearch(ObjList, obj).
 Se puede usar como un elemento dentro de un TreeSet.

Ejemplo (Ordenación de una Lista usando Comparable). El interfaz Empleado es


implementado por la clase Persona, que a su vez implementa el interfaz Comparable
(redefiniendo compareTo). Así, compareTo() define la ordenación natural de las personas,
siendo ésta por apellidos, nombre y edad.

// Empleado.java
public interfaz Empleado{
public String getNombre();
public String getApellidos();
public int getEdad();
// No se añade compareTo, ya que está declarado en la interfaz Comparable
}

// Persona.java
public class Persona implements Comparable, Empleado{
private String nombre, apellidos;
private int edad;

Estructuras de Datos Página 13 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

public Persona(String n, String a, int e){ nombre = n; apellidos = a; edad = e;}

public String getNombre(){return nombre;}


public String getApellidos(){return apellidos;}
public int getEdad(){return edad;}

public boolean equals(Object o)


{
if(!(o instanceof Persona))
return false;
else{
Persona p = (Persona)o;
return p.nombre.equals(nombre)
&& p.apellidos.equals(apellidos)
&& p.edad==edad; //son enteros int
}
}
public String toString(){
return apellidos + ", " + nombre + " (" + edad +")" ;
}

public int compareTo(Object o){


Persona p = (Persona)o; //Eleva ClassCastException

//si o no es una Persona


int cmp = apellidos.compareTo(p.apellidos); //Primero por apellidos
if (cmp == 0)
{
cmp = nombre.compareTo(p.nombre); //Segundo por nombre
if (cmp == 0)
{
cmp = edad - p.edad; // Finalmente por edad
}
}
return cmp;
}
}

//TestEmpleado.java
import java.util.*;
public class TestEmpleado{
public static void main(String args[]){
List c = new ArrayList();

Empleado e1 = new Persona("Pepe", "Lopez Perez", 25);


Empleado e2 = new Persona("Lola", "Lopez Aguilar", 23);
Empleado e3 = new Persona("Pepe", "Lopez Perez", 21);
Empleado e4 = new Persona("Antonio", "lopez Perez", 25);
Empleado e5 = new Persona("Alicia", "Sanchez Olmo", 21);
c.add(e1); c.add(e2); c.add(e3); c.add(e4); c.add(e5);

Estructuras de Datos Página 14 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

//Compara dos Empleados


if(((Persona)e1).compareTo((e2))>0){ // MUY IMPORTANTE EL CASTING
System.out.println(e1 + " es mayor que " + e2);
}
else{
System.out.println(e1 + " es menor o igual que " + e2);
}

//Imprime la lista original


System.out.println("Lista Original:");
System.out.println(c);

//Ordena e imprime la lista ordenada según la ordenación natural de Persona


System.out.println("Ordenación:");
Collections.sort(c); //Ordena
System.out.println(c);

}
}

La salida de este programa es:

Lopez Perez, Pepe (25) es mayor que Lopez Aguilar, Lola (23)
Lista Original:
[Lopez Perez, Pepe (25), Lopez Aguilar, Lola (23), Lopez Perez, Pepe (21), lopez Perez,
Antonio (25), Sanchez Olmo, Alicia (21)]
Ordenación:
[Lopez Aguilar, Lola (23), Lopez Perez, Pepe (21), Lopez Perez, Pepe (25), Sanchez Olmo,
Alicia (21), lopez Perez, Antonio (25)]

Nótese que tras la ordenación, la persona “lopez Perez, Antonio (25)” es la última al comenzar
su apellido por minúscula.

4.2. Interfaz Comparator

Si una clase ya tiene un criterio de ordenación natural (interfaz Comparable) y se desea tener
un criterio de ordenación diferente, por ejemplo descendente o dependiente de otros campos,
es necesario crear una clase que implemente dicho criterio. Esta clase, que se denomina
comparador, es independiente de la clase objeto de la ordenación y deberá implementar la
interfaz Comparator del paquete java.util. Un comparador es por tanto una clase que define
un criterio de ordenación de otras clases.

La interfaz Comparator declara el método compare en la forma:

public int compare(Object o1, Object o2);

Así, la clase comparadora deberá implementar la interfaz Comparator, y por tanto el método
compare, de la siguiente forma:

public class MiComparador implements Comparator{


public int compare(Object o1, Object o2){
<implementación del criterio de comparación>
}
}

Estructuras de Datos Página 15 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

El método compare() devuelve un entero negativo, cero o positivo según su primer argumento
sea anterior, igual o posterior al segundo (así asegura un orden ascendente). La
implementación debe asegurar que:

 signo(compare(x,y) debe ser igual a - signo(compare(y,x)) para todas las x, y. Esto


implica que compare(x, y) lanzará una excepción solo si compare(y, x) la lanza.
 La relación es transitiva: compare(x,y) > 0 && compare(y,z) > 0 implican compare(x z)
> 0.
 compare(x,y)==0 implica signo(compare(x,z)==sgn(compare(y,z)) para todo z. Este
método lanzará la excepción ClassCastException si el tipo de los argumentos impide la
comparación por este Comparator.

Es muy importante que compare() sea compatible con el método equals() de los objetos que
hay que mantener ordenados. Su implementación debe cumplir unas condiciones similares a las
de compareTo().

Los objetos que implementa la interfaz Comparator pueden ser utilizados en las siguientes
situaciones (especificando un orden distinto al natural):

 Como argumento a un constructor TreeSet o TreeMap (con la idea de que las mantengan
ordenadas de acuerdo con dicho comparador).
 En los métodos de ordenación Collections.sort(List, Comparator) y Arrays.sort(Object[],
Comparator).
 En los métodos de búsqueda Collections.binarySearch(List, Object, Comparator) y
Arrays.binarySearch(List, Object, Comparator).

Ejemplo (Ordenación de una lista usando Comparator). Este ejemplo es similar al


anterior. De hecho, usa la interfaz Empleado definida en el ejemplo anterior. Se añaden dos
comparadores para hacer diferentes ordenaciones, en concreto: ComparadorIgnoraMayMin,
cuyo método compare() compara dos Personas con el mismo criterio que compareTo() del
ejemplo anterior, sólo que en este caso no se distinguen mayúsculas y minúsculas; el otro
comparador es ComparadorEdad, que usa la edad como criterio de comparación entre
personas (si son de la misma edad, compara por apellidos y nombre).

//ComparadorIgnoraMayMin
import java.util.*;
class ComparadorIgnoraMayMin implements Comparator {
public int compare(Object o1, Object o2) {
Persona p1 = (Persona)o1; //Eleva ClassCastException si o1 no es Persona
Persona p2 = (Persona)o2; //Eleva ClassCastException si o2 no es Persona
//Es igual que compareTo de Persona pero usando compareToIgnoreCase()
int cmp = p1.getApellidos().compareToIgnoreCase(p2.getApellidos());
if (cmp == 0){
cmp = p1.getNombre().compareToIgnoreCase(p2.getNombre());
if (cmp == 0){
cmp = p1.getEdad() - p2.getEdad();
}
}
return cmp;
}
}

// ComparadorEdad.java
import java.util.*;

Estructuras de Datos Página 16 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

class ComparadorEdad implements Comparator {


public int compare(Object o1, Object o2) {
Persona p1 = (Persona)o1; //Eleva ClassCastException si o1 no es Persona
Persona p2 = (Persona)o2; //Eleva ClassCastException si o2 no es Persona
int cmp = p1.getEdad() - p2.getEdad(); //Primero por edad
if (cmp == 0)
{
cmp = p1.getApellidos().compareTo(p2.getApellidos());//Luego por apellidos
if (cmp == 0)
{
cmp = p1.getNombre().compareTo(p2.getNombre()); //finalmente por nombre
}
}
return cmp;
}
}

// TestEmpleadoComparators.java
import java.util.*;
public class TestEmpleadoComparators{
public static void main(String args[]){
List c = new ArrayList();

Empleado e1 = new Persona("Pepe", "Lopez Perez", 25);


Empleado e2 = new Persona("Lola", "lopez Aguilar", 23);
Empleado e3 = new Persona("Pepe", "Lopez Perez", 21);
Empleado e4 = new Persona("Antonio", "Lopez Perez", 25);
Empleado e5 = new Persona("Alicia", "Sanchez Olmo", 21);
c.add(e1); c.add(e2); c.add(e3); c.add(e4); c.add(e5);

//Imprime Lista Original


System.out.println("Lista Original:");
System.out.println(c);

//Ordenación natural (Comparable de Persona)


System.out.println("Ordenación Natural (Comparable):");
Collections.sort(c);
System.out.println(c);

//Ordenación sin diferenciar entre Mayúsculas y Minúsculas (Comparator)


System.out.println("Ordenación Natural sin MayMin (Comparator):");
Collections.sort(c, new ComparadorIgnoraMayMin());
System.out.println(c);

//Ordenación por Edad (Comparator)


System.out.println("Ordenación por edad(Comparator):");
Collections.sort(c, new ComparadorEdad());
System.out.println(c);
}
}

La salida de este programa es:

Lista Original:
[Lopez Perez, Pepe (25), lopez Aguilar, Lola (23), Lopez Perez, Pepe (21), Lopez Perez,
Antonio (25), Sanchez Olmo, Alicia (21)]

Ordenación Natural (Comparable):


[Lopez Perez, Antonio (25), Lopez Perez, Pepe (21), Lopez Perez, Pepe (25), Sanchez Olmo,
Alicia (21), lopez Aguilar, Lola (23)]

Estructuras de Datos Página 17 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

Ordenación Natural sin MayMin (Comparator):


[lopez Aguilar, Lola (23), Lopez Perez, Antonio (25), Lopez Perez, Pepe (21), Lopez
Perez, Pepe (25), Sanchez Olmo, Alicia (21)]

Ordenación por edad(Comparator):


[Lopez Perez, Pepe (21), Sanchez Olmo, Alicia (21), lopez Aguilar, Lola (23), Lopez
Perez, Antonio (25), Lopez Perez, Pepe (25)]

Process Exit...

4.3. ¿Cuándo usar Comparable y Comparator?

Usaremos Comparable para definir el orden natural de una clase C, entendiendo por orden
natural aquel que se utilizará normalmente o simplemente por convenio. Así, diremos que los
objetos de clase C son comparables.

Por otro lado, implementaremos nuevas clases (C1 … Cn) que extiendan el interfaz Comparator
por cada ordenación nueva que necesitemos distinta a la natural para la clase C. Así tendremos
una “librería de comparadores” (C1 … Cn) para la clase C.

Estructuras de Datos Página 18 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

5 Utilidades para objetos contenedores: Clase java.util.Collections


La clase Collections (no confundir con la interfaz Collection, en singular) es una clase que
define un buen número de métodos static con diversas finalidades. Dado que son estáticos, la
llamada a dichos métodos es: Collections.metodo(<argumentos>)

Los más interesantes son los siguientes (todos los métodos aquí expuestos retornan o toman
como argumentos una List, excepto max y min que toman como argumento una Collection):

5.1. Ordenación

public static void sort(List);


public static void sort(List, Comparator);

Ordenan la lista, bien de forma ascendente según el orden natural (establecido por el interfaz
Comparable), o bien de la forma especificada por Comparator. Tal ordenación es estable, es
decir, los elementos iguales no son desplazados. Lanzan las siguientes excepciones:
ClassCastException, si un elemento en la lista tiene un tipo que impide su comparación con el
resto los interfaces Comparable o Comparator; UnsupportedOperationException, si la lista no es
modificable (su iterator no soporta la operación set).

5.2. Inversión del Orden

public static void reverse(List);


public static Comparator reverseOrder();

El métodos reverse(List) ordena la lista en el sentido inverso de la posición actual de sus


elementos (independiente del valor de los elementos). No realiza una ordenación descendente.

El método reverseOrder() devuelve un Comparator que introduce una ordenación inversa a la


impuesta por el orden natural de un contenedor de objetos que implementan el interfaz
Comparable. El Comparator devuelto implementa el método compare() de forma que devuelve
el resultado de compareTo()cambiado de signo. Puede utilizarse donde se espere un
Comparator, por ejemplo: Arrays.sort(list, Collections.reverseOrder()).

5.3. Búsqueda

public static int binarySearch(List, Object);


public static int binarySearch(List, Object, Comparator);

Buscan el objeto en la lista y devuelven la posición (int) de tal objeto (resultado 0 o positivo). Si
no está en la lista devuelve (-(pos_mayor)-1); donde pos_mayor es la posición del primer
elemento en la lista mayor que el buscado, o el tamaño de la lista si el elemento buscado es el
mayor de todos.

La lista debe estar ordenada de forma ascendente. Esto puede lograrse con un orden natural
para el primer método, como por ejemplo sort(List); o bien usando un Comparator para el
segundo método: sort(List,Comparator). Los resultados no son especificados si la lista esta
desordenada. No se asegura cuál será el elemento devuelto si existen duplicados.

Lanzan la excepción ClassCastException si algún elemento en la lista tiene un tipo que impide
su comparación.

Estructuras de Datos Página 19 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

NOTA: Sobre el sentido de la ordenación impuesto por sort y el sentido en que esta ordenada
la lista o matriz que binarySearch examina, la API especifica que en estos dos métodos, tanto
en la clase Arrays como en la clase Collections, el sentido de la ordenación sea ascendente.
Esto es debido a que las clases que implementan Comparable o Comparator lo hacen en la
forma descrita en la API. Siguiendo estas recomendaciones los comparadores que creásemos
serían siempre ascendentes. Para lograr una ordenación inversa utilizaríamos el método
reverseOrder de la clase Collection. Alternativamente puede implementarse un Comparator o
Comparable descendente y utilizarse en ambos métodos. Luego, lo realmente importante es
mantener el sentido con el que se ha ordenado un contenedor a la hora de buscar en él. Es
conveniente también recordar que los tipos primitivos y sus envolturas implementan
Comparable en sentido ascendente.

5.4. Copiar Lista

public static void copy(List, List);

Copia los elementos residentes en el segundo argumento en el primero. Si el tamaño del


destino es mayor que el de la fuente, los restantes elementos no se ven afectados. Lanza
IndexOutOfBoundsException si el tamaño del destino es menor que el de la fuente, y
UnsupportedOperationException si el iterator de la lista no soporta la operación set.

5.5. Rellenar una Lista

public static void fill(java.util.List, Object);

Remplaza todos los elementos de la lista por el objeto especificado. No modifica el tamaño de la
lista. Se ejecuta en un tiempo lineal.
Lanza UnsupportedOperationException si el iterator de la lista no soporta la operación set.

5.6. Máximos y Mínimos

public static Object max(Collection);


public static Object max(Collection, Comparator);
public static Object min(Collection);
public static Object min(Collection, Comparator);

Devuelven el objeto que en la colección especificada sea el menor, o el mayor de todos, de


acuerdo al orden natural (establecido por Comparable) de tales objetos, o según el Comparator
especificado.

5.7. Constantes

public static final java.util.List EMPTY_LIST;


public static final java.util.Set EMPTY_SET;

Existen tres constantes (campos estáticos finales) de tipo List y Set que son inicializados para
contener un objeto vacío del tipo correspondiente. Sus nombres son EMPTY_LIST y EMPTY_SET.
Sirven para representar contenedores vacíos.

Estructuras de Datos Página 20 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

Ejemplo:
import java.util.*;

public class TestCollections{


public static void main(String args[]){
List c = new ArrayList();
int pos;

Empleado e1 = new Persona("Pepe", "Lopez Perez", 25);


Empleado e2 = new Persona("Lola", "lopez Aguilar", 23);
Empleado e3 = new Persona("Pepe", "Lopez Perez", 21);
Empleado e4 = new Persona("Antonio", "Lopez Perez", 25);
Empleado e5 = new Persona("Alicia", "Sanchez Olmo", 21);
c.add(e1); c.add(e2); c.add(e3); c.add(e4); c.add(e5);

//Imprime Lista Original


System.out.println("Lista Original:");
System.out.println(c);

//Ordenación natural (Comparable de Persona) y Búsqueda


System.out.println("Ordenación Natural (Comparable) y Búsqueda:");
Collections.sort(c); //Ordenación natural usando Comparable
System.out.println(c);
pos=Collections.binarySearch(c, e4);
System.out.println("Búsqueda: La posición de <" + e4 + "> es " + pos);
//Ordenación por Edad (Comparator) y Búsqueda
System.out.println("Ordenación por edad y búsqueda:");
Collections.sort(c, new ComparadorEdad());//Ordenación usando ComparadorEdad
System.out.println(c);
pos=Collections.binarySearch(c, e4, new ComparadorEdad());
System.out.println("Búsqueda: La posición de <" + e4 + "> es " + pos);

//Máximo y mínimo
Empleado eMax = (Empleado) Collections.max(c, new ComparadorEdad());
Empleado eMin = (Empleado) Collections.min(c, new ComparadorEdad());
System.out.println("Empleado más viejo: " + eMax);
System.out.println("Empleado más joven: " + eMin);

}
}

Estructuras de Datos Página 21 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

6 Clase Arrays (ampliación)


Esta clase es muy parecida a la case Collections vista anteriormente, por lo que sus métodos los
veremos con menor nivel de detalle. La invocación a tales métodos también es similar:
Arrays.metodo(<argumentos>)

6.1. Tratar Matriz como Lista

public static List asList(Object[]);

Retorna una vista (no una copia) de la matriz pasada como argumento implícito, que puede ser
manipulada como si fuera una lista. Como dicha lista es respaldada por una matriz no pueden
agregarse o eliminarse elementos a ella. Cualquier modificación estructural (del número de
elementos) provoca UnsupportedOperationException debido a la no implementación de los
métodos opcionales del interfaz List en la lista retornada. El resto de cambios en la lista son
reflejados en la matriz y viceversa.

6.2. Métodos similares a los de Collections

public static void sort(tipoPrimitivo[]);


public static void sort(tipoPrimitivo[], Comparator);
public static void sort(Object[]);
public static void sort(Object[], Comparator);

public static int binarySearch(tipoPrimitivo[], unPrimitivo);


public static int binarySearch(Object[], Object);
public static int binarySearch(Object[], Object, Comparator);

public static void fill(tipoPrimitivo[], unPrimitivo);


public static void void fill(tipoprimitivo[], int fromIndex,
int toIndex, unPrimitivo);
public static void void fill(Object[], Object);
public static void void fill( Object[], int fromIndex, int toIndex, Object);

7 Clase java.lang.Math
La case Math del paquete estándar java.lang contiene métodos estáticos para realizar
operaciones matemáticas básicas como exponencial, logaritmos, raiz cuadrada, funciones
trigonométricas, etc. La invocación a tales métodos o constantes es similar a los de Collections
y Arrays: Math.metodo(<argumentos>)

Los miembros más interesantes de esta clase son:

public final class java.lang.Math {


// Constantes
public static final double E;
public static final double PI;
// Funciones trigonométricas
double sin(double);
double cos(double);
double tan(double);
double asin(double);
double acos(double);

Estructuras de Datos Página 22 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

double atan(double);
double toRadians(double);
double toDegrees(double);
// Funciones básicas
double exp(double);
double log(double);
double log10(double);
double sqrt(double);
double ceil(double);
double floor(double);
double pow(double, double);
<int/long/float/double> abs(<int/long/float/double>);
<int/long/float/double> max(<int/long/float/double>, <int/long/float/double>);
<int/long/float/double> max(<int/long/float/double>, <int/long/float/double>);
< . . . >
}

Estructuras de Datos Página 23 de 24


ED - Enseñanza Básica Tema 1: Introducción al JCF

8 Bibliografía
• Documentación de la API de Java:

o Página principal de JCF:


http://java.sun.com/j2se/1.5.0/docs/guide/collections/index.html

o Tutorial de JCF - Introducción:


http://java.sun.com/docs/books/tutorial/collections/intro/index.html

o Especificación de la interfaz Comparable:


http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Comparable.html

o Especificación de la interfaz Comparator:


http://java.sun.com/j2se/1.5.0/docs/api/java/util/Comparator.html

o Especificación de la interfaz Iterator:


http://java.sun.com/j2se/1.5.0/docs/api/java/util/Iterator.html

o Especificación de la interfaz ListIterator:


http://java.sun.com/j2se/1.5.0/docs/api/java/util/ListIterator.html

o Especificación de la clase Collections:


http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collections.html

o Especificación de la clase Arrays:


http://java.sun.com/j2se/1.5.0/docs/api/java/util/Arrays.html

o Especificación de la clase Math:


http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Math.html

• Thinking in Java, 3rd Edition. Bruce Eckel. Prentice Hall, 2002. Capítulo 11.
http://www.mindview.net/Books/TIJ/

• Aprenda Java como si Estuviera en Primero. Capítulo 4.


http://mat21.etsii.upm.es/ayudainf/aprendainf/Java/Java2.pdf

Estructuras de Datos Página 24 de 24

También podría gustarte