Colecciones Java: la interfaz de lista

    Introducci贸n

    los Marco de colecciones de Java es un marco fundamental y esencial que cualquier desarrollador de Java fuerte deber铆a conocer como la palma de su mano.

    Una colecci贸n en Java se define como un grupo o colecci贸n de objetos individuales que act煤an como un solo objeto.

    Hay muchas clases de colecci贸n en Java y todas ellas extienden el java.util.Collection y java.util.Map interfaces. En su mayor铆a, estas clases ofrecen diferentes formas de formular una colecci贸n de objetos dentro de un solo objeto.

    Colecciones de Java es un marco que proporciona numerosas operaciones sobre una colecci贸n: b煤squeda, clasificaci贸n, inserci贸n, manipulaci贸n, eliminaci贸n, etc.

    Esta es la primera parte de una serie de art铆culos de las colecciones de Java:

    • La interfaz de lista (est谩s aqu铆)
    • La interfaz de conjunto
    • La interfaz del mapa
    • Las interfaces Queue y Deque

    Problemas con matrices

    Matrices son una de las primeras cosas con las que se presenta un nuevo desarrollador Java horneado.

    Una matriz de objetos, muy similar a una colecci贸n, representa un grupo de objetos como un solo objeto.

    Tanto una matriz como una colecci贸n son un objeto que representa muchos otros objetos, entonces, 驴por qu茅 se necesitan ambos?

    Consideremos una colecci贸n de productos:

    Product door = new Product("Wooden Door", 35);
    Product floorPanel = new Product("Floor Panel", 25);
    

    Tenemos una puerta de madera y un panel de puerta, con un peso de 35 kg y 25 kg respectivamente. Estos son POJOs, lo que significa que solo tienen un par de m茅todos getter y setter y un toString() m茅todo.

    Con esto, es bastante sencillo crear una instancia de una matriz de estos objetos:

    Product[] products = { door, floorPanel };
    

    Impresi贸n de matrices

    Hay muchas razones por las que alguien querr铆a imprimir una matriz, incluida la depuraci贸n o la devoluci贸n de los resultados:

    System.out.println(products);
    

    Sin embargo, cuando intentamos imprimirlo, recibimos un resultado que no es muy amigable para los humanos:

    com.demo.collections.Product;@14ae5a5
    

    De hecho, necesitamos confiar en la clase auxiliar java.util.Arrays para obtener un resultado sensato:

    System.out.println(Arrays.toString(products));
    

    Esta vez, estamos viendo algo que tiene m谩s sentido:

    [Product{name="Wooden Door", weight=35}, Product{name="Floor Panel", weight=25}]
    

    Agregar y eliminar elementos

    Nuestra colecci贸n de productos se hizo m谩s grande y se supone que debemos agregar una ventana a la matriz:

    final Product window = new Product("Window", 15);
    products = add(window, products);
    System.out.println(Arrays.toString(products));
    
    
    public static Object[] add(Object[] array, Object... elements) {
        Object[] tempArray = new Object[array.length + elements.length];
        System.arrayCopy(array, 0, tempArray, 0, array.length);
    
        for(int i = 0; i < elements.length; i++) {
            tempArray[array.length+i] = elements[i];
            return tempArray;
        }
    }
    

    Este es exactamente el tipo de situaci贸n en la que probablemente prefieras pegar un tiro en la pierna, porque las matrices no cambian de tama帽o.

    Para agregar un elemento, tenemos que hacer una copia de la matriz en una nueva matriz, instanciarla con los nuevos elementos y asignar la nueva matriz a nuestra variable de referencia.

    Las matrices son una construcci贸n de bajo nivel y no nos brindan muchas caracter铆sticas, mientras que las colecciones est谩n hechas para combatir ese mismo problema y ofrecen muchas caracter铆sticas y una gran funcionalidad.

    Colecciones

    Java Collections Framework se env铆a con el propio JDK. Vale la pena recordar que en los viejos tiempos, especialmente para las personas que escrib铆an c贸digo C, los desarrolladores no ten铆an estructuras de datos para elegir. De hecho, la gente sol铆a escribir sus propias estructuras de datos, lo que algunos hacen incluso hoy.

    Existen razones leg铆timas de rendimiento por las que alguien podr铆a encontrar una estructura de datos personalizada ideal para un proyecto espec铆fico. Pero, para la mayor铆a de los desarrolladores, confiar en el marco existente es una buena opci贸n.

    Java se utiliza para construir aplicaciones y sistemas grandes y complejos. Dicho esto, casi todas las aplicaciones de Java terminar谩n usando el marco de colecciones en un momento u otro.

    Todas las clases de recopilaci贸n tienen una estructura de datos subyacente que est谩n implementando: 谩rboles, tablas hash, mapas hash, colas, etc. . No hay necesidad de reinventar la rueda si ya est谩 servida, a menos que desee practicar y desafiarse a s铆 mismo para encontrar soluciones innovadoras y alternativas.

    Echaremos un vistazo a algunos tipos diferentes de colecciones en Java:

    • Liza – Una colecci贸n secuencial (ordenada). Realizan un seguimiento de las posiciones de todos los elementos, como matrices, y ofrecen operaciones de b煤squeda, iteraci贸n y vista de rango de sus elementos. Las listas pueden tener elementos duplicados.
    • Conjuntos – Aplica restricciones de unicidad: no puede contener elementos duplicados. No se preocupa por el orden de iteraci贸n dentro de s铆 mismo, ya que modela la abstracci贸n matem谩tica del conjunto. Los conjuntos no ofrecen m谩s funciones que las heredadas de las colecciones.
    • Colas – Introducir orden de modificaci贸n, es decir, si agregas elementos en un orden determinado, tienes que seguir un orden determinado. Las colas ofrecen operaciones adicionales de inserci贸n, eliminaci贸n e inspecci贸n de sus elementos. Es 煤nico que las colas sigan el FIFO Estructura (primero en entrar, primero en salir).
    • Deques – Al igual que las colas, las colas de dos extremos (abreviadas a deques) ofrecen adem谩s la posibilidad de realizar operaciones en elementos de ambos lados de la cola.
    • Mapas – Aunque las implementaciones de java.util.Map no se consideran “colecciones verdaderas”, ofrecen operaciones de visualizaci贸n de colecciones que pr谩cticamente les permiten la manipulaci贸n a nivel de colecci贸n. Esta colecci贸n no es una colecci贸n de valores individuales, sino pares. Se trata de asociaciones entre claves y valores 煤nicos (mapas) que se pueden buscar a partir de esas claves. Es importante tener en cuenta que las claves son 煤nicas y cada clave est谩 asociada con un valor, pero un valor puede estar asociado con m谩s de una clave.

    Interfaz Collection

    Como se mencion贸 anteriormente, todas las interfaces de colecci贸n dentro de la API de Java extienden una interfaz com煤n: java.util.Collection. Esta interfaz principal proporciona todas las funciones de colecciones comunes.

    Cada subinterfaz tiene varias implementaciones y algunas de estas subinterfaces ofrecen operaciones adicionales:

    El punto clave a entender es que cada interfaz define el comportamiento y las caracter铆sticas funcionales donde podemos utilizar m煤ltiples estructuras de datos mientras que las implementaciones definen las caracter铆sticas de desempe帽o, utilizan una estructura de datos espec铆fica y son instanciables.

    Los m茅todos m谩s utilizados en el Collection interfaz son:

    Nombre del m茅todo Descripci贸n del m茅todo
    contiene (elemento)Verdadero si el elemento est谩 en esta colecci贸n, falso en caso contrario

    Talla()Obtener la cantidad de elementos de la colecci贸n
    esta vacio()Verdadero si size () == 0, falso en caso contrario
    agregar (elemento)Agrega el elemento al comienzo de esta colecci贸n
    addAll (colecci贸n)Agregue todos los elementos de la colecci贸n de argumentos a esta colecci贸n
    eliminar (elemento)Quitar el elemento de esta colecci贸n
    removeAll (colecci贸n)Eliminar todos los elementos de la colecci贸n de argumentos a esta colecci贸n
    retener todo ()Eliminar todos los elementos de esta colecci贸n que no est谩n en la colecci贸n de argumentos
    containsAll (colecci贸n)Verdadero si todos los elementos de la colecci贸n de argumentos est谩n en esta colecci贸n
    claro()Eliminar todos los elementos de esta colecci贸n

    Liza

    La primera interfaz, y probablemente la m谩s utilizada: java.util.List.

    Cada elemento de la lista tiene un 铆ndice, un int valor que define su posici贸n. El recuento de indexaci贸n comienza en 0, lo mismo que la indexaci贸n que podemos encontrar con las matrices.

    los java.util.List La interfaz tambi茅n agrega un par de otras operaciones m谩s all谩 de las operaciones habituales de recolecci贸n:

    • get(int index)
    • set(int index, Object object)

    Estas operaciones se explican por s铆 mismas y no necesitan m谩s explicaci贸n. Sin embargo, echemos un vistazo a algunos ejemplos de c贸digo.

    Agregar un elemento

    Utilizando el add() m茅todo, podemos agregar f谩cilmente objetos a nuestra lista:

    List<String> products = new ArrayList<>();
    products.add("Mug");
    products.add("Wallet");
    products.add("Phone");
    System.out.println(products);
    

    Salida:

    [Mug, Wallet, Phone]
    

    Nota: Estamos creando una instancia de la lista como su implementaci贸n concreta ArrayList. En la mayor铆a de los casos, usar铆amos esta implementaci贸n para una lista.

    Otra nota: Puede especificar el tama帽o inicial de ArrayList a trav茅s del constructor para evitar cambiar el tama帽o si conoce un tama帽o definitivo.

    La interfaz tambi茅n proporciona otra versi贸n del add() m茅todo, incluido un 铆ndice. En este caso, agregamos el elemento al 铆ndice dado, y si el 铆ndice ya est谩 tomado por otro elemento, todos los elementos despu茅s del agregado se desplazan a la derecha en uno:

    products.add(2, "Pen");
    System.out.println(products);
    

    Salida:

    [Mug, Wallet, Pen, Phone]
    

    Recuperando elementos

    Utilizando el get() m茅todo con el 铆ndice dado, podemos recuperar un elemento espec铆fico en la lista:

    System.out.println(products.get(0));
    

    Salida:

    [Mug]
    

    Eliminar elementos

    Utilizando el remove() m茅todo, podemos eliminar un elemento de la lista. Llamar a este m茅todo devolver谩 el elemento y desplazar谩 los elementos posteriores un 铆ndice hacia atr谩s, para completar el hueco ahora existente en la secuencia:

    System.out.println(products.remove(1));
    

    Salida:

    [Wallet]
    

    Elementos de ajuste

    Utilizando el set() m茅todo, podemos reemplazar un elemento existente dado un 铆ndice:

    products.set(1, "Book");
    
    System.out.println(products);
    

    Salida:

    [Mug, Book, Phone]
    

    Buscando elementos

    Utilizando el indexOf() m茅todo, tambi茅n podemos buscar valores, dado un 铆ndice. Si la b煤squeda falla y no existe ning煤n objeto con el 铆ndice dado, la lista devolver谩 -1. En el caso de varios objetos iguales, la lista devolver谩 solo el primer 铆ndice.

    Utilizando el lastIndexOf() devolver谩 el 煤ltimo 铆ndice del elemento dado.

    System.out.println(products.indexOf(5));
    

    Salida:

    -1
    

    Elementos iterativos

    Aunque es posible iterar con for y enhanced-for bucles, la interfaz proporciona dos nuevas clases de ayuda que nos permiten iterar a trav茅s de listas: Iterator y ListIterator:

    for (Iterator<E> iterator = list.iterator(); iterator.hasNext(); ) {
        E element = iterator.next();
        element.someMethod();
        iterator.remove(element);
        //...
    }
    
    for (ListIterator<E> iterator = list.listIterator(); iterator.hasNext(); ) {
        E element = iterator.next();
        element.someMethod();
        iterator.remove(element);
        //...
    }
    

    Nota: Los ListIterator ofrece m谩s control sobre la iteraci贸n de la lista, ya que permite el recorrido en ambas direcciones, mientras que Iterator solo permite el recorrido en una direcci贸n.

    Adem谩s, Java 8 nos presenta una forma realmente sencilla de imprimir los elementos utilizando una referencia de m茅todo:

    list.forEach(System.out::println);
    

    Implementaciones y diferencias

    Lista de arreglo: implementos java.util.List como una matriz de redimensionamiento din谩mico:

    • Buena implementaci贸n de prop贸sito general
    • Usado como predeterminado
    • M谩s simp谩tico cach茅 de CPU

    Lista enlazada: implementos java.util.List como una lista doblemente enlazada:

    • Peor rendimiento para muchas operaciones
    • 脷selo al agregar elementos al principio
    • 脷selo al agregar / quitar mucho

    Generalmente hablando, ArrayList es mucho m谩s utilizado que LinkedList. Y para citar a Joshua Bloch, el hombre que escribi贸 LinkedList:

    “驴Alguien realmente usa LinkedList? Yo lo escrib铆 y nunca lo uso”.

    Comparaci贸n de rendimiento

    Debido a sus diferentes naturalezas, estas implementaciones tienen diferentes enfoques y tiempos de ejecuci贸n de m茅todos.

    Dependiendo de los requisitos, tendr谩 que elegir cu谩l usar. En general, por su doble vinculaci贸n, LinkedList es bueno para adiciones y remociones frecuentes mientras que ArrayList es bueno para buscar debido al acceso aleatorio.

    Conclusi贸n

    El marco de las Colecciones de Java es un marco fundamental que todo desarrollador de Java deber铆a saber utilizar.

    En el art铆culo, hemos hablado de las colecciones en general, los problemas con las matrices y c贸mo el framework las combate. Luego, pasamos a las implementaciones de esta interfaz, sus ventajas y desventajas, as铆 como las operaciones que seguramente usar谩 en un momento u otro.

     

    Etiquetas:

    Deja una respuesta

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