Como utilizar los ArrayList de Java. Arrays de memoria dinámica.

COMPARTIR EN REDES SOCIALES

En post anteriores estuvimos viendo Arrays de memoria estática, donde vimos que era necesario asignar un tamaño máximo de número de elementos que podía contener nuestro Array. En este post vamos a ver otra estructura de datos en Java, los ArrayList, cuya principal ventaja es que se basan en memoria dinámica, es decir, podemos almacenar tantos elementos como queramos en los mismos. Si lees todo el post aprenderás como utilizar los ArrayList de Java de manera correcta.

Veremos los siguientes puntos:

  1. ¿ Qué es un ArrayList ?
  2. ¿ Cómo se crea un ArrayList ?
  3. ¿ Qué tipo de elementos puede tener un ArrayList ?
  4. ¿ Cómo se insertan los elementos en un ArrayList ?
  5. ¿ Cómo se accede a los elementos de un ArrayList ?
  6. ¿ Cómo sé cuántos elementos tiene un ArrayList almacenados ?
  7. ¿ Cómo se itera sobre un ArrayList ?
  8. Ejemplo completo de utilización de ArraysList
  9. Ordenación de los elementos de un ArrayList
  10. Búsqueda de elementos en un ArrayList
  11. Comparar si 2 ArrayList son iguales

Vamos al lio.

1. ¿ Qué es un ArrayList ?

Un ArrayList es una clase definida en Java que que funciona de forma similar a un Array, pero que nos permite insertar en ella tantos elementos como queramos ya que está basada en memoria dinámica. Nosotros como programadores no nos preocupamos de la memoria, será la máquina virtual de Java la que se preocupe por nosotros de la memoria. Si visitamos la documentación de Java podemos ver su definición:

https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html

Os dejo aquí una captura de sus principales métodos:

Documentación JavaDoc sobre la clase ArrayList de Java
JavaDoc sobre la clase ArrayList
Documentación JavaDoc sobre la clase ArrayList de Java
JavaDoc sobre la clase ArrayList

2. ¿ Cómo se crea un ArrayList ?

El ArrayList, al ser una clase de Java se crea de la siguiente forma:

ArrayList<String> miArrayList = new ArrayList<String>();

Cabe destacar que es necesario parametrizar que tipo de objeto vamos a guardar dentro de nuestro ArrayList entre los símbolos <>.

3. ¿ Qué tipo de elementos puede tener un ArrayList ?

Podemos almacenar cualquier tipo de Objeto, veamos algunos ejemplos:

ArrayList<String> misCadenas = new ArrayList<String>();
ArrayList<Integer> misNumeros = new ArrayList<Integer>();
ArrayList<Float> misNumerosEnComaFlotante = new ArrayList<Float>();
ArrayList<Double> misNumeroEnComaFlotanteMasPrecisos = new ArrayList<Double>();
ArrayList<Boolean> misBooleanos = new ArrayList<Boolean>();
ArrayList<BigDecimal> misBigDecimals = new ArrayList<BigDecimal>();
ArrayList<MiClase> misClasesPersonalizadas = new ArrayList<MiClase>();
ArrayList<Object> miArrayListDeCualquierTipoDeObjeto = new ArrayList<Object>();

Es importante destacar que no se pueden almacenar tipos de datos primitivos, y que por lo tanto, habrá que utilizar su representación en clase, os pongo una tabla a continuación:

intInteger
floatFloat
doubleDouble
booleanBoolean
Correspondencia de tipos primitivos de Java a Clases

Es importante destacar 2 cosas:

  • Se pueden almacenar nuestras propias clases. Supongamos que hemos creado una clase llamada Alumno, el ArrayList se crearía de la siguiente forma: ArrayList<Alumno> misAlumnos= new ArrayList<Alumno>();
  • Podemos almacenar objetos de diferente tipo aprovechando que toda clase de Java hereda de Object. Esto lo veremos en profundidad más adelante, pero por ahora quedaros con lo siguiente: ArrayList<Object> miArrayListDeCualquierTipoDeObjeto = new ArrayList<Object>();

4. ¿ Cómo se insertan los elementos en un ArrayList ?

Para insertar elementos en un ArrayList tenemos que utilizar el método «add». Este método nos permite insertar cualquier elemento de forma consecutiva, veamos un ejemplo con cadenas:

ArrayList<String> misCadenas = new ArrayList<String>();

misCadenas.add("Este");
misCadenas.add("es");
misCadenas.add("mi");
misCadenas.add("primer");
misCadenas.add("ArrayList");
misCadenas.add("de");
misCadenas.add("cadenas");

En la primera posición tendríamos la cadena «Este», en la segunda posición «es», en la tercera posición «mi» y así sucesivamente.

5. ¿ Cómo se accede a los elementos de un ArrayList ?

Para acceder a los elementos de un ArrayList se hace mediante el método «get», al cuál se le pasa como parámetro la posición del elemento al cuál queremos acceder, veamos un ejemplo:

System.out.println(misCadenas.get(0));
System.out.println(misCadenas.get(1));
System.out.println(misCadenas.get(2));
System.out.println(misCadenas.get(3));
System.out.println(misCadenas.get(4));
System.out.println(misCadenas.get(5));
System.out.println(misCadenas.get(6));

La salida del programa sería la siguiente:

Este
es
mi
primer
ArrayList
de
cadenas

Tened en cuenta que en Java siempre el primer elemento está en la posición 0.

6. ¿ Cómo sé cuántos elementos tiene un ArrayList almacenados ?

Los ArrayList tienen un método llamado «size» que nos devuelve el número de elementos que tiene almacenado el ArrayList. Veamos un ejemplo con las cadenas:

System.out.println(misCadenas.size());

La salida de la sentencia anterior sería la siguiente: 7, que es el número de cadenas que tenemos dentro de nuestro ArrayList de cadenas.

7. ¿ Cómo se itera sobre un ArrayList ?

La forma de iterar sobre un ArrayList es igual que la forma de iterar sobre los Arrays de memoria estática, es decir, mediante bucles: for, while, forEach

Mediante un bucle for:

for (int i = 0; i < misCadenas.size(); i++) {
    System.out.println(misCadenas.get(i));
}

Mediante un bucle while:

int i = 0;
		
while (i < misCadenas.size()) {
    System.out.println(misCadenas.get(i));
    i++;
}

Tanto en los bucles for y while, fijaos que la condición de parada utiliza la llamada a la función «size()» sobre el ArrayList, ya que nos devuelve el número de elementos que contiene.

Mediante forEach:

for (String cadena: misCadenas) {
    System.out.println(cadena);
}

8. Ejemplo completo de utilización de ArraysList

Vamos a calcular el sumatorio de todos los elementos que tenemos en el ArrayList

ArrayList<Integer> misNumeros = new ArrayList<Integer>();

misNumeros.add(7);
misNumeros.add(14);
misNumeros.add(17);
misNumeros.add(19);
misNumeros.add(199);
misNumeros.add(299);
		
int sumatorio = 0;
		
for (int i = 0; i < misNumeros.size(); i++) {
	sumatorio = sumatorio + misNumeros.get(i);
}
		
System.out.println("El sumatorio es: " + sumatorio);

9. Ordenación de los elementos de un ArrayList

Para ordenar los elementos de un ArrayList podemos utilizar varias formas:

  • Mediante la clase Collections
  • Mediante comparadores

Mediante la clase Collections

ArrayList<Integer> misNumeros = new ArrayList<Integer>();

misNumeros.add(1);
misNumeros.add(189);
misNumeros.add(233);
misNumeros.add(33);
misNumeros.add(199);
misNumeros.add(299);
		
Collections.sort(misNumeros);
		
for (Integer numero: misNumeros) {
    System.out.println(numero);
}

Simplemente pasamos al método sort de la clase Collections nuestro ArrayList.

La salida de nuestro programa sería la siguiente:

1
33
189
199
233
299

Mediante comparadores

Mediante comparadores necesitamos crear una clase que implemente la interfaz Comparator<TipoDeDatos>, en nuestro caso será de Integers, vamos a ver el código:

public class ComparadorIntegers implements Comparator<Integer>{
	
	@Override
	public int compare(Integer num1, Integer num2) {
		// TODO Auto-generated method stub
		if (num1 == num2) {
			return 0;
		}else if (num1 > num2) {
			return 1;
		}else {
			return -1;
		}
	}
}

Funciona de forma muy sencilla, nos obliga a implementar un método llamado compare que devuelve un entero, devolveremos un numero positivo si el num1 > num2, devolveremos 0 si num1 == 0 y -1 si num1 < num2.

¿ Cómo se utilizaría este comparador en nuestro ejemplo ?:

public class Main{
	
	public static void main(String [] args) {
		ArrayList<Integer> misNumeros = new ArrayList<Integer>();
		
		misNumeros.add(1);
		misNumeros.add(189);
		misNumeros.add(233);
		misNumeros.add(33);
		misNumeros.add(199);
		misNumeros.add(299);
		
		misNumeros.sort(new ComparadorIntegers());
		
		for (Integer numero: misNumeros) {
			System.out.println(numero);
		}
	}
}

Simplemente mediante esta línea: misNumeros.sort(new ComparadorIntegers());

La salida del programa será la siguiente:

1
33
189
199
233
299

Cabe destacar que mediante comparadores podemos ordenar cualquier tipo de Objeto, vamos a ver un ejemplo, crearemos una clase llamada Producto con dos atributos, un id y un nombre, veamos el código:

public class Producto {
	private int id;
	private String nombre;
	
	public Producto(int id, String nombre) {
		this.id = id;
		this.nombre = nombre;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getNombre() {
		return nombre;
	}

	public void setNombre(String nombre) {
		this.nombre = nombre;
	}
	
}

Veamos ahora nuestro comparador de productos:

public class ComparadorProductos implements Comparator<Producto>{

	@Override
	public int compare(Producto p1, Producto p2) {
		if (p1.getId() == p2.getId()) {
			return 0;
		}else if (p1.getId() > p2.getId()) {
			return 1;
		}else {
			return -1;
		}
	}

}

Se basa en comparar p1 y p2 mediante los métodos getId.

¿ Y cómo se utiliza en nuestro método principal ?

public static void main(String [] args) {
	//Cracion de los productos
	Producto producto1 = new Producto(10, "Tuerca");
	Producto producto2 = new Producto(1, "Tornillo");
	Producto producto3 = new Producto(5, "Clavo");
	Producto producto4 = new Producto(3, "Destornillador");
	Producto producto5 = new Producto(15, "Martillo");
	Producto producto6 = new Producto(6, "Pegamento");
		
	//Creacion del ArrayList
	ArrayList<Producto> productos = new ArrayList<>();
		
	//Añadimos los productos al ArrayList
	productos.add(producto1);
	productos.add(producto2);
	productos.add(producto3);
	productos.add(producto4);
	productos.add(producto5);
	productos.add(producto6);
		
	//Iteramos sobre nuestros productos sin ordenar
	System.out.println("Productos sin ordenar");
	for (Producto producto: productos) {
		System.out.println(producto.getId());
	}
	
	System.out.println("-----------------------------");
		
	//Ordenamos nuestros productos
	productos.sort(new ComparadorProductos());
		
	System.out.println("Productos ordenados");
	//Iteramos sobre nuestros productos ordenados
	for (Producto producto: productos) {
		System.out.println(producto.getId());
	}
}

La salida de nuestro programa:

Productos sin ordenar
10
1
5
3
15
6
Productos ordenados
1
3
5
6
10
15

Como se puede apreciar hemos ordenado nuestros productos por su id de forma muy sencilla.

10. Búsqueda de elementos en un ArrayList

Para realizar búsquedas en un ArrayList lo podemos hacer de diferentes formas en función de nuestra casuística:

  • De forma manual
  • Mediante búsqueda binaria en la clase Collections

De forma manual

Para realizar una búsqueda manual solo tenemos que recorrer todo nuestro ArrayList buscando el elemento en concreto:

public static void main(String [] args) {
	//Creacion de los productos
	Producto producto1 = new Producto(10, "Tuerca");
	Producto producto2 = new Producto(1, "Tornillo");
	Producto producto3 = new Producto(5, "Clavo");
	Producto producto4 = new Producto(3, "Destornillador");
	Producto producto5 = new Producto(15, "Martillo");
	Producto producto6 = new Producto(6, "Pegamento");
		
	//Creacion del ArrayList
	ArrayList<Producto> productos = new ArrayList<>();
		
	//Añadimos los productos al ArrayList
	productos.add(producto1);
	productos.add(producto2);
	productos.add(producto3);
	productos.add(producto4);
	productos.add(producto5);
	productos.add(producto6);
		
	boolean encontrado = false;
	int indiceBusqueda = -1;
		
	for (int i = 0; i < productos.size() && !encontrado; i++) {
		if (productos.get(i).getId() == 10) {
			encontrado = true;
			indiceBusqueda = i;
		}
	}
		
	System.out.println("ID: " + productos.get(indiceBusqueda).getId() + ", NOMBRE: " + productos.get(indiceBusqueda).getNombre());
}

Recorremos todo el ArrayList, cuando encontremos el id que estamos buscando, cambiamos la variable «encontrado» a «true» y guardamos el índice para luego poder acceder a él.

La salida del programa será la siguiente:

ID: 10, NOMBRE: Tuerca

Mediante búsqueda binaria en la clase Collections

public static void main(String [] args) {
	//Creacion de los productos
	Producto producto1 = new Producto(10, "Tuerca");
	Producto producto2 = new Producto(1, "Tornillo");
	Producto producto3 = new Producto(5, "Clavo");
	Producto producto4 = new Producto(3, "Destornillador");
	Producto producto5 = new Producto(15, "Martillo");
	Producto producto6 = new Producto(6, "Pegamento");
		
	//Creacion del ArrayList
	ArrayList<Producto> productos = new ArrayList<>();
		
	//Añadimos los productos al ArrayList
	productos.add(producto1);
	productos.add(producto2);
	productos.add(producto3);
	productos.add(producto4);
	productos.add(producto5);
	productos.add(producto6);
		
	//Ordenamos nuestros productos
	productos.sort(new ComparadorProductos());
		
	//Búsqueda binaria sobre nuestro ArrayList
	int indiceBusqueda = Collections.binarySearch(productos, new Producto(10, null), new ComparadorProductos());
		
	System.out.println("ID: " + productos.get(indiceBusqueda).getId() + ", NOMBRE: " + productos.get(indiceBusqueda).getNombre());
}

La clave aquí está en partir del ArrayList ordenado y utilizar el comparador que ya hemos creado anteriormente. Mediante esta sentencia es todo lo que necesitamos: int indiceBusqueda = Collections.binarySearch(productos, new Producto(10, null), new ComparadorProductos());

La salida del programa será la siguiente:

ID: 10, NOMBRE: Tuerca

11. Comparar si 2 ArrayList son iguales

Vamos a partir de la base de 2 ArrayList de enteros, luego lo extenderemos a nuestro ArrayList de Productos:

Comparar si 2 ArrayList de enteros son iguales

//Nuestro primer ArrayList
ArrayList<Integer> misNumeros = new ArrayList<Integer>();

misNumeros.add(1);
misNumeros.add(2);
misNumeros.add(3);
misNumeros.add(4);
misNumeros.add(5);
misNumeros.add(6);
		
//Nuestro segundo ArrayList
ArrayList<Integer> misNumeros2 = new ArrayList<Integer>();

misNumeros2.add(1);
misNumeros2.add(2);
misNumeros2.add(3);
misNumeros2.add(4);
misNumeros2.add(5);
misNumeros2.add(6);
		
if (misNumeros.equals(misNumeros2)) {
	System.out.println("Los 2 Arrays son iguales");
}

Utilizamos el metodo equals, y esto funciona porque Integer ya tiene implementado el método equals, por lo tanto funciona, pero ¿ Qué pasa si utilizando nuestra clase producto intentamos hacer lo mismo ?

//Creacion de los productos del primer Array
Producto producto1 = new Producto(10, "Tuerca");
Producto producto2 = new Producto(1, "Tornillo");
Producto producto3 = new Producto(5, "Clavo");
Producto producto4 = new Producto(3, "Destornillador");
Producto producto5 = new Producto(15, "Martillo");
Producto producto6 = new Producto(6, "Pegamento");
		
//Creacion del primer ArrayList
ArrayList<Producto> productos = new ArrayList<>();
		
//Añadimos los productos al primer ArrayList
productos.add(producto1);
productos.add(producto2);
productos.add(producto3);
productos.add(producto4);
productos.add(producto5);
productos.add(producto6);
		
//Creacion de los productos del segundo Array
Producto producto7 = new Producto(10, "Tuerca");
Producto producto8 = new Producto(1, "Tornillo");
Producto producto9 = new Producto(5, "Clavo");
Producto producto10 = new Producto(3, "Destornillador");
Producto producto11 = new Producto(15, "Martillo");
Producto producto12 = new Producto(6, "Pegamento");
		
//Creacion del segundo ArrayList
ArrayList<Producto> productos2 = new ArrayList<>();
		
//Añadimos los productos al segundo ArrayList
productos2.add(producto7);
productos2.add(producto8);
productos2.add(producto9);
productos2.add(producto10);
productos2.add(producto11);
productos2.add(producto12);
		
//Realizamos la Comparacion
if (productos.equals(productos2)) {
	System.out.println("Los 2 Arrays son iguales");
}else {
	System.out.println("Los 2 Arrays no son iguales");
}

La salida de nuestro programa:

Los 2 Arrays no son iguales

¿ Por qué nuestro programa nos está diciendo que los 2 arrays no son iguales si realmente contienen los mismos elementos ? La respuesta es bastante sencilla y avanzada al mismo tiempo, porque al no tener el método «equals» en la clase producto implementado está comparando direcciones de memoria, y obviamente la dirección de memoria de producto1 no es igual a la dirección de memoria de producto7 aunque su contenido sea el mismo. Vamos a implementar el método equals en Producto y volvemos a ejecutar el programa anterior:

public class Producto{
	private int id;
	private String nombre;
	
	public Producto(int id, String nombre) {
		this.id = id;
		this.nombre = nombre;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getNombre() {
		return nombre;
	}

	public void setNombre(String nombre) {
		this.nombre = nombre;
	}
	
	@Override
	public boolean equals(Object p2) {
		Producto producto2 = (Producto)p2;
		if (this.getId() == producto2.getId() && this.getNombre().equals(producto2.getNombre())) {
			return true;
		}else {
			return false;
		}
	}
	
}

Ahora la salida de nuestro programa cambia drásticamente, ya que si realiza la comparación correctamente:

Los 2 Arrays son iguales

Si te ha gustado el artículo deja un comentario en la caja de comentarios para apoyar el blog!

Si te interesa el tema visita los siguientes enlaces:

  1. Implementación de un ArrayList de Strings desde 0
  2. Implementación de un ArrayList Genérico en Java

COMPARTIR EN REDES SOCIALES

Deja una respuesta

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