Entendiendo un ArrayList

Entendiendo un ArrayList

Un arreglo tiene una desventaja notable: necesitas saber cuántos elementos serán necesarios en el arreglo al crearlo y, después, te quedas atado a esa decisión. Al igual que un StringBuilder, un ArrayList puede ajustar su capacidad en tiempo de ejecución según sea necesario. Como un arreglo, un ArrayList es una secuencia ordenada que permite duplicados.

Al igual que cuando usamos Arrays.sort, ArrayList requiere una importación. Para usarlo, debes tener una de las siguientes dos declaraciones en tu clase:

En esta sección, veremos cómo crear un ArrayList, métodos comunes, autoboxing, conversión y clasificación.

Creando un ArrayList

Al igual que con el StringBuilder, existen tres maneras de crear un ArrayList:

La primera instrucción crea un ArrayList con espacio para el número predeterminado de elementos, pero aún no asigna ninguna posición. La segunda crea un ArrayList con un número específico de posiciones, pero nuevamente, sin asignar nada. El último ejemplo le dice a Java que queremos hacer una copia de otro ArrayList. Copiamos el tamaño y el contenido de ese ArrayList. Cabe señalar que lista2 está vacía en este ejemplo, así que no es particularmente interesante.

Aunque estos son los únicos tres constructores que necesitas conocer, también debes aprender algunas variantes de ellos. Los ejemplos anteriores eran la forma antigua, previa a Java 5, de crear un ArrayList. Todavía funcionan, y es importante que sepas que siguen siendo válidos. Sin embargo, también debes conocer la nueva y mejorada manera. Java 5 introdujo los genéricos, que permiten especificar el tipo de clase que contendrá el ArrayList.

Java 5 te permite indicarle al compilador cuál será el tipo, especificándolo entre < y >. A partir de Java 7, incluso puedes omitir ese tipo en el lado derecho. Aún se requieren < y > lo que se conoce como el operador diamante porque <> se asemeja a un diamante.

Usando var con ArrayList

Ahora que se puede usar var para ocultar los tipos de datos, surge toda una nueva serie de preguntas que pueden hacerse sobre los genéricos. Considera este código que mezcla ambos conceptos:

El tipo de var es ArrayList<String>. Esto significa que puedes agregar una cadena o iterar sobre los objetos String. ¿Y qué sucede si usamos el operador diamante con var?

Créelo o no, esto compila. El tipo de var es ArrayList<object>. Dado que no se especificó un tipo para el genérico, Java debe asumir la superclase final

Esto es algo tonto e inesperado, por lo que, por favor, no lo escribas. ¿Ahora puedes descubrir por qué esto no compila?

El tipo de var é ArrayList<Object). Como no hay un tipo en el operador diamante, Java tiene que asumir la opción más genérica posible. Por lo tanto, elige Object, la superclase base. Agregar una cadena a la lista está bien, ya que puedes agregar cualquier subclase de Object. Sin embargo, al iterar en el ciclo, necesitas usar el tipo Object en lugar de String.

Cuando pensabas que ya sabías todo sobre cómo crear un ArrayList, hay más cosas que debes saber. ArrayList implementa una interfaz llamada List. En otras palabras, un ArrayList es un List. Mientras tanto, debes saber que puedes almacenar un ArrayList en una variable de referencia de tipo List, pero no al revés. La razón es que List es una interfaz, y las interfaces no pueden ser instanciadas.

Usando un ArrayList

ArrayList tiene muchos métodos, pero solo necesitas conocer un puñado de ellos, incluso menos de los que aprendiste para String y StringBuilder. Antes de continuar, notarás algo nuevo en las firmas de los métodos: una clase llamada E. No te preocupes, no es realmente una clase. E se utiliza por convención en genéricos para significar "cualquier clase que este arreglo pueda contener".

Si no especificaste un tipo al crear el ArrayList, E significa Object. De lo contrario, significa la clase que especifiques entre < y >.

También debes saber que ArrayList implementa el método toString(), por lo que puedes ver fácilmente su contenido solo con imprimirlo. Los arreglos, por defecto, no muestran una salida tan amigable.

add()

El método add() inserta un nuevo valor en el ArrayList. Las firmas del método son las siguientes:

No te preocupes por el valor booleano de retorno, siempre devuelve true. Está ahí porque otras clases de la familia Collections necesitan un valor de retorno en la firma al añadir un elemento. Como add() es el método más crítico de ArrayList que necesitas conocer, te mostraremos algunos ejemplos de cómo funciona. Comencemos con el caso más simple:

add() hace exactamente lo que esperamos: almacena la cadena en el espacio vacío del ArrayList. Luego hace lo mismo con el booleano. Esto está bien, ya que no especifiqué un tipo para ArrayList, por lo que el tipo es Object, que incluye todo excepto tipos primitivos. Puede que no sea lo que pretendíamos, pero el compilador no lo sabe. Ahora, usemos genéricos para indicarle al compilador que solo queremos permitir objetos String en nuestro ArrayList:

Esta vez, el compilador sabe que solo se permiten objetos String y evita que se intente añadir un booleano. Ahora, intentemos agregar varios valores en diferentes posiciones.

Cuando una pregunta tenga código que añada objetos en posiciones indexadas, dibújalo de manera que no pierdas el control de qué valor está en qué índice. En este ejemplo, la línea 5 añade "hawk" al final de la lista birds. Luego, la línea 6 añade “robin” en el índice 1 de birds, que ahora es el final.

La línea 7 añade “blue jay” en el índice 0, que es el inicio de birds. Finalmente, la línea 8 añade “cardinal” en el índice 1, que ahora está cerca del medio de birds.

remove()

Los métodos remove() eliminan el primer valor coincidente en el ArrayList o eliminan el elemento en un índice especificado. Las firmas del método son las siguientes:

Esta vez, el valor booleano de retorno nos indica si se eliminó una coincidencia. El tipo de retorno E es el elemento que realmente fue eliminado. A continuación, mostramos cómo usar estos métodos:

La línea 6 intenta eliminar un elemento que no está en birds. Devuelve false porque dicho elemento no existe. La línea 7 intenta eliminar un elemento que sí está en birds y devuelve true. Observa que solo elimina una coincidencia. La línea 8 elimina el elemento en el índice 0, que es el último elemento que queda en el ArrayList. Como llamar a remove(). con un entero usa el índice, un índice que no existe lanzará una excepción. Por ejemplo, birds.remove(100) lanza una IndexOutOfBoundsException. También existe un método método removeIf () que usa expresiones lambda.

set()

El método set() reemplaza uno de los elementos del ArrayList sin cambiar su tamaño.

La firma del método es la siguiente:

El tipo de retorno E es el elemento que fue reemplazado. El siguiente código muestra cómo usar este método:

La línea 16 añade un elemento al arreglo, cambiando su tamaño a 1. La línea 18 reemplaza ese elemento, y el tamaño permanece en 1. La línea 20 intenta reemplazar un elemento que no está en el ArrayList. Como el tamaño es 1, el único índice válido es 0. Java lanza una excepción porque eso no está permitido.

isEmpty() e size()

Los métodos isEmpty() y size() verifican cuántos espacios están en uso. Las firmas de los métodos son las siguientes:

El siguiente código muestra cómo usar estos métodos:

Al principio, birds tiene un tamaño de 0 y está vacío. Tiene una capacidad mayor a 0, pero, al igual que con StringBuilder, no usamos la capacidad para determinar el tamaño o la longitud. Después de agregar elementos, el tamaño se vuelve positivo y ya no está vacío. Nota que isEmpty() es un método conveniente para size() == 0.

clear()

El método clear() proporciona una forma fácil de eliminar todos los elementos del ArrayList. La firma del método es la siguiente:

Después de llamar a clear(), birds vuelve a ser un ArrayList vacío con un tamaño de 0.

contains()

El método contains() verifica si un valor específico está en el ArrayList. La firma del método es la siguiente:

El siguiente ejemplo muestra cómo usar este método:

Este método llama a equals() en cada elemento del ArrayList para ver si hay alguna coincidencia. Como String implementa equals(), esto funciona bien.

equals()

Finalmente, ArrayList tiene una implementación personalizada de equals(), por lo que puedes comparar dos listas para ver si contienen los mismos elementos en el mismo orden.

El siguiente ejemplo muestra cómo hacerlo:

En la línea 33, los dos objetos ArrayList son iguales. Una lista vacía es definitivamente el mismo elemento en el mismo orden. En la línea 35, los objetos ArrayList no son iguales porque los tamaños son diferentes. En la línea 37, son iguales nuevamente porque el mismo elemento está en cada uno. En la línea 40, no son iguales. El tamaño es el mismo y los valores son los mismos, pero no están en el mismo orden.

¡Ahora estás listo para crear un ArrayList! Nos vemos en el próximo artículo.

💡
Las opiniones y comentarios emitidos en este artículo son propiedad única de su autor y no necesariamente representan el punto de vista de Listopro.

Listopro Community da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.