Java

Conceptos básicos de Java & Spring Framework – Colecciones

Colecciones en Java.

Java provee de un API para el tratamiento de colecciones de objetos, dicha librería no es otra cosa que un conjunto de varias clases e interfaces que permiten manipular de manera sencilla y fácil colecciones de Objetos.

Pero quizás te estés preguntando ¿Que es una colección?. Una colección es un conjunto de elementos agrupados para un fin determinado. Algunos ejemplos de colecciones que comúnmente un desarrollador encontrara en su día a día:

  • La colección de permisos de un usuario
  • La colección de transacciones realizadas por un cliente
  • La colección de tarjetas asociadas a una cuenta bancaria
  • La colección de estatus por las que paso una transacción
  • La colección de empleados de un departamento
  • Etc.

El listado anterior de ejemplos de colecciones es muy corto; te sorprenderías la cantidad de veces que se usan las colecciones en el desarrollo de sistemas. Debido a su uso intensivo es importante aprender las operaciones mas básicas que se pueden realizar con ellas.

En cierta forma las colecciones se parecen un poco a los arreglos, pero a diferencia de éstos las colecciones pueden cambiar de tamaño dinámicamente y se pueden realizar operaciones mas avanzadas.

Si quisiéramos podríamos escribir nuestras propias clases para manipular colecciones de objetos pero como mencione anteriormente Java ya cuenta con un API bastante amplio y sobre todo probado para esta tarea. Como buenos desarrolladores no deberíamos reinventar la rueda a menos que deseemos una funcionalidad muy especifica con colecciones y ya hayamos investigado que no existe esa funcionalidad en dicha API de Java.

Operaciones básicas con las Colecciones

Algunas de las operaciones básicas de las colecciones son:

  • Inserción de elementos
  • Eliminación de elementos
  • Actualización de elementos
  • Búsqueda de elementos
  • Recorrido de elementos
  • Ordenamiento de elementos

Mas adelante veremos como realizar las operaciones anteriores.

Organización de la API de colecciones de Java

La mayoría del API para el manejo de colecciones en Java esta en el paquete java.util aunque Java también tiene un conjunto de colecciones concurrentes en el paquete java.util.concurrent. En este breve tutorial solo hablare de las clases e interfaces del primer paquete.

El API Collections de Java esta organizado principalmente en dos grupos: Collections y Map’s. Para entender este API es necesario mostrar como están organizadas las interfaces de estos dos grupos, posteriormente veremos algunas de las clases que implementan a algunas interfaces.

A continuación se muestra de forma gráfica al estilo UML la jerarquía de herencia del primer grupo del API, las Collections:
UML_Colecciones_Java

Observa como todas son interfaces para las cuales la API Collections ya tiene clases que las implementan. No confundir una interface con una clase, este tutorial se centra en gran medida en explicar como usar las clases que implementan a cada una de las interfaces anteriores, aunque para algunas interfaces explicare como implementarlas nosotros mismos. No se explicaran todas las clases a detalle porque hacerlo fácilmente ocuparía el capitulo completo de un libro pero si mencionare los métodos y operaciones mas comunes.

A continuación se muestra de forma gráfica al estilo UML la jerarquía de herencia del segundo grupo del API, los Maps:

Al igual que para las colecciones, para los mapas la API tiene clases que implementan las interfaces anteriores. Como vez son bastantes interfaces de la API collections (sumando los dos grupos), no es necesario que te las aprendas todas pero si que entiendas como están organizadas en su jerarquía.

Quizas te estes preguntando ¿porque tantas interfaces?, bueno recordemos dos ventajas de utilizar interfaces:

  • Se separa la especificacion de las operaciones de la implementacion.
  • Al tener la sepacion anterior es mas facil reemplazar una clase por otra que implemente la misma interfaz pero con funcionalidades extra o mejor performance. Recordemos el principio que dice que debemos “programar para interfaces, no para implementaciones”.

Empezare explicando a las interfaces y clases del primer grupo; las collections.

Como implementar la interface Iterable

Si deseamos crear nuestra propia clase de tipo Collection, es necesario implementar esta interface, a continuación muestro un ejemplo de como hacer esto. El ejemplo consta de 3 archivos java y son los siguientes:

Empleado.java

Como se puede observar esta clase es de las llamadas POJO y esta compuesta de 2 constructores, 3 atributos (y sus correspondientes getters y setters), el método toString() se ha sobrescrito para mostrar posteriormente el contenido de un objeto Empleado, es importante OFUSCAR los datos que sean sensibles a mostrar. Esta clase la utilizaremos en la siguiente clase.

ColeccionEmpleados.java

Observa como esta clase implementa a la interface Iterable, podríamos utilizar generics pero en este caso utilizamos específicamente la clase Empleado. El unico metodo obligatorio de implementar de esta interface es el método iterator() pero se han agregado un constructor y el método utilitario agregar() para añadir empleados a un Vector.

TestColecciones .java

Para ejemplificar el uso de la clase personalizada de tipo collection ColeccionEmpleados la siguiente clase muy sencilla que agrega 3 empleados y posteriormente los muestra por pantalla.

La interface Collection

Si observas el primero de los dos diagramas la interface java.util.Collection es una de las interfaces raiz del API Collections de Java. Recuerda que una interface no se puede instanciar pero si se pueden instanciar las clases que la implementen. A continuación un listado de las interfaces que heredan de esta interface:

  • List
  • Set
  • Queue
  • SortedSet
  • NavigableSet
  • Deque

La interface Collection basicamente define una conjunto de metodos que comparten cada unas de las sub-interfaces anteriores, es decir, agrupa la funcionalidad general que todas las colecciones ofrecen, esto es muy importante entenderlo. A continuación se muestran la mayoría de estos métodos que agrupa al estilo de UML:

Como se puede observar son varios métodos y son comunes a todas las colecciones. Aqui puedes consultar la documentación oficial de estos métodos (Java 6), y Aquí la documentación de estos métodos para Java 7.

Es importante recordar que hasta ahora solo he hablado de las interfaces del API Collections de Java. Recuerda que en las interfaces se especifica que debe hacerse pero no como se hace. Serán las clases que implementen estas interfaces las que describan la lógica del comportamiento de los métodos declarados en la interface. Si deseas repasar el tema de las interfaces te invito a leer la entrega II de este curso de Spring Framework donde hable un poco sobre este tema.

Clases que implementan a la interface List

La interface java.util.List es una de las mas utilizadas del API Collections, existen 4 clases que implementan a esta interface a continuación se muestran en forma gráfica:

Cuando utilizamos colecciones en Java por lo general utilizamos las clases implementadoras, como las anteriores. Pero quizás te estés preguntando porque existen 4 clases ¿Que no basta con una?; lo que pasa es que cada cada clase tiene sus ventajas y desventajas principalmente en cuanto a rendimiento y las debes de utilizar dependiendo de lo que mas te convenga para cumplir tu requerimiento, veamos algunas características que las distinguen:

  • ArrayList. La principal ventaja de un ArrayList sobre un Array normal es que su tamaño es dinámico, es decir, su tamaño crece cuando se le van añadiendo elementos (en un arreglo su tamaño se especifica al momento de crearse). Esta clase es muy rápida accediendo a elementos, pero es lenta la inserción y el borrado al inicio o a la la mitad de la lista; la inserción es lenta porque todos los elementos posteriores a la posición donde se desea insertar se deben “recorrer” hacia adelante para hacer un espacio para el nuevo elemento, la eliminación es lenta porque los elementos posteriores a la posición que ocupaba el elemento eliminado se deben recorrer hacia atrás para rellenar el espacio vació. Utiliza un ListIterator para desplazarse por los elementos. Por lo general estarás utilizando esta lista sino conoces las ventajas de las demás.
  • LinkedList. Esta lista en realidad es una lista enlazada. El acceso a los elementos se hace de manera secuencial, es decir, si deseamos acceder al elemento 50 debemos empezar a buscarlo desde el inicio e ir avanzando al siguiente de uno en uno, su principal desventaja es esa. Sin embargo, su principal ventaja es que al ser una lista enlazada (cada nodo apunta al anterior y siguiente nodo) la eliminación es rápida debido a que solo hay que modificar el nodo anterior y siguiente para “ignorar” al elemento eliminado, todos los demás nodos permanecen intactos.
  • Vector. Al igual que ArrayList, un Vector contiene internamente un array para persistir el contenido de los elementos. Estas dos clases se parecen mucho pero no son iguales; por defecto la capacidad del vector se incrementa al doble de su tamaño cuando se queda sin espacio, mientras que un ArrayList incrementa en un 50% su capacidad cuando no tiene mas espacio para añadir mas elementos a su array interno. Sin embargo en el vector podemos especificar el tamaño que crecerá el array interno si nos quedamos sin espacio, no así con un ArrayList. Como se sabe, siempre es mejor establecer el tamaño de la lista al tamaño máximo de la lista (que podría tener). Dependiendo del uso que le demos a estas clases podríamos tener un gran impacto en el rendimiento del programa. Recuerda, sino sabes el tamaño máximo que tendrá la lista pero sabes a que velocidad va creciendo, siempre usa un Vector con un tamaño de crecimiento pequeño.
  • Stack. Esta clase igualmente implementa a la interface List, indirectamente, pues extiende a la clase Vector. En teoría de colas y estructura de datos se utiliza el termino LIFO (Ultimo en entrar, primero en salir) para referirse a la forma de accesar a los elementos de este tipo de estructuras. Para entender mejor el concepto imaginemos el clásico ejemplo de los platos apilados unos sobre otros; si yo agrego un plato es una operación de inserción y se representa con la operación PUSH, si yo retiro un plato es una operación de eliminación y se representa con la operación POP. Ambas operaciones pop y push siempre se realizan sobre la cima de la pila.

    stack_concept

A continuación mostrare como utilizar estas clases con una serie de ejemplos muy cortos en donde realizaremos las operaciones mas básicas.

Manejando Listas utilizando la clase ArrayList

En el siguiente fragmento de código se muestran las operaciones mas comunes con la clase ArrayList:

Por defecto se pueden insertar todo tipo de objetos en una lista, pero también podemos limitar que tipos de objetos manipulara la lista. Esto lo hacemos al momento de instanciar la clase como se observa a continuación:

En la lista anterior empleadosList solo se pueden insertar objetos de tipo Empleado y si se intenta insertar otro tipo de objeto, el compilador se quejara con un mensaje indicando que el método add no acepta otro tipo de argumento que no sea de tipo Empleado.

Manejando Listas utilizando la clase LinkedList

En el siguiente fragmento de código se muestran las operaciones mas comunes con la clase LinkedList:

Como se observa, las operaciones que se pueden realizar son las mismas que las de ArrayList y la diferencia principal esta en la velocidad de acceso, inserción y eliminación que se mencionaron previamente.

Manejando Listas utilizando la clase Vector

En el siguiente fragmento de código se muestran las operaciones mas comunes con la clase Vector:

Con el código anterior se obtendría la siguiente salida:

1
2
3
4
5
6
7
Auto [id=1, marca=Mercedes, pais=Alemania]
Auto [id=2, marca=Peugeot, pais=Francia]

Como utilizar pilas con la clase Stack

Ahora mismo estas visualizando esta pagina web, si das click en un enlace, tu navegador web colocara la URL de la pagina actual en una pila y mostrara el contenido del enlace al que diste click, posteriormente si vuelves a dar click en otro hipervinculo en la nueva pagina el navegador repetira la operacion colocando la nueva URL en la cima y asi sucesivamente. Como sabes tu puedes volver a visitar las paginas anteriores si das click en el boton Atras; con lo cual el navegador web sacara la URL de mas arriba (la ultima) y la pintara y asi puedes volver por las paginas anteriores con lo que el navegador repetira la operacion de ir sacando las URLs conforme fueron insertadas en la pila. Lo anterior es ejemplo de donde se podrian utilizar este tipo de estructura de datos llamadas Pilas.

Como se menciono anteriormente, las operaciones principales de la clase Stack son pop() y push(), repasemos:

  • push() Coloca un elemento en la cima
  • pop() Quita un elemento de la cima
  • isEmpty() Devuelve true solo si la pila tiene algun elemento

Para mostrar como se usa esta clase haremos dos ejemplos; el primero es el mas sencillo, consistira en agregar 5 elementos a una pila y posteriormente los ira sacando uno a uno para mostrarlos en pantalla. En el segundo ejemplo resolveremos el clasico problema de compiladores que consiste en verificar si una determinada sentencia o instrucción está equilibrada en cuanto a número de paréntesis, corchetes o llaves de apertura y cierre.

Stack :: Ejemplo 1

Observa como la operacion pop() saca los elementos; el ultimo en entrar es el primero en salir:
Ejemplo 1 Stack Salida

Stack :: Ejemplo 2

A continuación la salida en pantalla del ejemplo 2:

ej2StackSalida

Hasta aqui se ha explicado a groso modo lo que es la API para manejo de colecciones en Java y algunos ejemplos. Quisiera explicar cada una de las clases implementadoras de las interfaces mostradas en los 2 diagramas anteriores (colecciones y mapas) pero este articulo se volveria bastante largo. Ademas, pienso continuar explicando con ejemplos cada una de esas clases en articulos posteriores.

Espero al menos a uno le sirva esta introducción a esta API.
Hasta pronto, saludos.

Acerca de notaspro

Desarrollador JEE y amante de las nuevas tecnologías de desarrollo.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *