¡Hola! En lecciones anteriores, profundizamos en las matrices y revisamos ejemplos comunes de trabajo con matrices. En esta lección, haremos una revisión más detallada en Java ArrayList. En general, las matrices son muy útiles. Y, como ya habrás notado, puedes hacer mucho con ellos :) Pero las matrices tienen una serie de deficiencias.
  • Tamaño limitado. Necesita saber cuántos elementos debe contener su matriz en el momento de crearla. Si subestimas, entonces no tendrás suficiente espacio. Si se sobrestima, la matriz permanecerá medio vacía, lo que también es malo. Después de todo, todavía está asignando más memoria de la necesaria.

  • Una matriz no tiene métodos para agregar elementos. Siempre debe indicar explícitamente el índice de la posición donde desea agregar un elemento. Si especifica accidentalmente el índice de una posición ocupada por algún valor que necesita, se sobrescribirá.

  • No hay métodos para eliminar un elemento. Un valor solo se puede "poner a cero".

public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat[] cats = new Cat[3];
       cats[0] = new Cat("Thomas");
       cats[1] = new Cat("Behemoth");
       cats[2] = new Cat("Lionel Messi");

       cats[1] = null;

      
      
       System.out.println(Arrays.toString(cats));
   }

   @Override
   public String toString() {
       return "Cat{" +
               "name='" + name + '\'' +
               '}';
   }
}
Salida: [Cat{name='Thomas'}, null, Cat{name='Lionel Messi'}] Afortunadamente, los creadores de Java son muy conscientes de las ventajas y desventajas de los arreglos y, por lo tanto, crearon una estructura de datos muy interesante llamada Java ArrayList . Hablando de la manera más simple posible, una ArrayList de Java es una matriz "mejorada" con muchas características nuevas.

Cómo crear una lista de arreglos

Es muy fácil de crear:

ArrayList<Cat> cats = new ArrayList<Cat>();
Ahora hemos creado una lista para almacenar objetos Cat . Tenga en cuenta que no estamos especificando el tamaño de ArrayList , porque puede expandirse automáticamente. ¿Cómo es esto posible? Es bastante simple, en realidad. Puede que te sorprenda, pero ArrayList en Java está construido sobre una matriz muy ordinaria :) Sí, contiene una matriz, y ahí es donde se almacenan nuestros elementos. Pero ArrayList en Java tiene una forma especial de trabajar con esa matriz:
  • Cuando se llena la matriz interna, ArrayList crea una nueva matriz internamente. El tamaño de la nueva matriz es el tamaño de la matriz anterior multiplicado por 1,5 más 1.

  • Todos los datos se copian de la matriz anterior a la nueva

  • El recolector de elementos no utilizados limpia la matriz anterior.
Este mecanismo permite que Java ArrayList (a diferencia de una matriz ordinaria) implemente un método para agregar nuevos elementos. es el add()metodo

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<Cat>();
   cats.add(new Cat("Behemoth"));
}
Los elementos nuevos se agregan al final de la lista. Ahora no hay riesgo de desbordar la matriz, por lo que este método es completamente seguro. Por cierto, ArrayList no solo puede encontrar un objeto por su índice, sino también viceversa: ¡puede usar una referencia para encontrar el índice de un objeto en ArrayList ! Para esto es el método indexOf() : Pasamos una referencia al objeto que queremos, e indexOf() devuelve su índice:

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   int thomasIndex = cats.indexOf(thomas);
   System.out.println(thomasIndex);
}
Salida: 0 Así es. De hecho, nuestro objeto thomas está almacenado en el elemento 0. Las matrices no solo tienen inconvenientes. También tienen ventajas incuestionables. Uno de ellos es la capacidad de buscar elementos por índice. Debido a que apuntamos a un índice, es decir, a una dirección de memoria específica, buscar una matriz de esta manera es muy rápido. ArrayListtambién sabe cómo hacerlo! El método get() implementa esto:

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   Cat secondCat = cats.get(1);

   System.out.println(secondCat);
}
Salida: Cat{name='Behemoth'} Además, puede averiguar fácilmente si ArrayList contiene un objeto en particular. Esto se hace usando el método ArrayList contains():

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   cats.remove(fluffy);
   System.out.println(cats.contains(fluffy));
}
El método comprueba si la matriz interna de ArrayList contiene el elemento y devuelve un valor booleano (verdadero o falso). Salida: falso Y otra cosa importante sobre la inserción. ArrayList le permite usar un índice para insertar elementos no solo al final de la matriz, sino en cualquier lugar. Tiene dos métodos para esto:
  • ArrayList add (índice int, elemento Cat)
  • Conjunto ArrayList (índice int, elemento Cat)
Como argumentos, ambos métodos toman el índice de la posición donde desea insertar y una referencia al objeto en sí. La diferencia es que insertar usando set() sobrescribe el valor anterior. Insertar usando add() primero cambia en uno todos los elementos desde [índice] hasta el final de la matriz, y luego agrega el objeto especificado en la posición vacía resultante.

Aquí hay un ejemplo:


public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);

   System.out.println(cats.toString());

   cats.set(0, lionel);// Now we have a list of 2 cats. Adding a 3rd using set

   System.out.println(cats.toString());
}
Salida: [[Cat{name='Thomas'}, Cat{name='Behemoth'}] [Cat{name='Lionel Messi'}, Cat{name='Behemoth'}] Teníamos una lista de 2 gatos . Luego insertamos otro como elemento 0 usando el método set() . Como resultado, el elemento antiguo ha sido reemplazado por uno nuevo.

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);

   System.out.println(cats.toString());

   cats.add(0, lionel);// Now we have a list of 2 cats. Adding a 3rd using add

   System.out.println(cats.toString());
}
Y aquí vemos que add() funciona de manera diferente. Mueve todos los elementos a la derecha y luego escribe el nuevo valor como elemento 0. Salida: [Cat{name='Thomas'}, Cat{name='Behemoth'}] [Cat{name='Lionel Messi'}, Cat{name='Thomas'}, Cat{name='Behemoth'}] Para limpiar completamente la lista, usamos el método clear() :

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();
   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   cats.clear();

   System.out.println(cats.toString());
}
Salida: [] Todo fue eliminado de la lista. Por cierto, tenga en cuenta: a diferencia de las matrices, ArrayList anula el método toString() y ya muestra la lista de forma adecuada como cadenas. Con arreglos ordinarios, tuvimos que usar la clase Arrays para esto. Y como mencioné Arrays : Java le permite "cambiar" fácilmente entre una matriz y una ArrayList , es decir, convertir una en otra. La clase Arrays tiene un método Arrays.asList() para esto. Lo usamos para obtener los contenidos como una matriz y pasarlos a nuestro constructor ArrayList :

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();


   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   Cat[] catsArray = {thomas, behemoth, lionel, fluffy};

   ArrayList<Cat> catsList = new ArrayList<>(Arrays.asList(catsArray));
   System.out.println(catsList);
}
Salida: [Cat{name='Thomas'}, Cat{name='Behemoth'}, Cat{name='Lionel Messi'}, Cat{name='Fluffy'}] También puedes ir en la dirección opuesta: get una matriz de un objeto ArrayList . Hacemos esto usando el método toArray() :

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();

   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   Cat[] catsArray = cats.toArray(new Cat[0]);

   System.out.println(Arrays.toString(catsArray));
}
Nota: pasamos una matriz vacía al método toArray() . Esto no es un error. Dentro de la clase ArrayList , este método se implementa de tal manera que pasar una matriz vacía aumenta su rendimiento. Solo tenga esto en cuenta para el futuro (por supuesto, puede pasar una matriz de un tamaño específico; eso también funcionará). Ah, sobre el tamaño. El tamaño actual de la lista se puede encontrar usando el método size() :

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>();


   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   System.out.println(cats.size());
}
Es importante comprender que, a diferencia de la propiedad de longitud de una matriz , el método ArrayList.size() devuelve la cantidad real de elementos, no la capacidad original. Después de todo, no especificamos un tamaño al crear ArrayList . Sin embargo, puede especificarlo: ArrayList tiene un constructor adecuado. Pero en términos de agregar nuevos elementos, esto no cambia su comportamiento:

public static void main(String[] args) {

   ArrayList<Cat> cats = new ArrayList<>(2);// create an ArrayList with an initial capacity of 2


   Cat thomas = new Cat("Thomas");
   Cat behemoth = new Cat("Behemoth");
   Cat lionel = new Cat("Lionel Messi");
   Cat fluffy = new Cat ("Fluffy");

   cats.add(thomas);
   cats.add(behemoth);
   cats.add(lionel);
   cats.add(fluffy);

   System.out.println(cats.size());
}
Resultado de la consola: 4 Hemos creado una lista de 2 elementos, pero se expandió silenciosamente cuando lo necesitábamos. Otra consideración es que si creamos una lista muy pequeña inicialmente, tendrá que expandirse más a menudo, lo que consumirá algunos recursos. Apenas mencionamos el proceso de eliminar elementos de una ArrayList en esta lección. Por supuesto, esto no se debe a que se nos haya olvidado. Hemos puesto este tema en una lección separada que conocerá más adelante :) Para reforzar lo que aprendió, le sugerimos que vea una lección en video de nuestro Curso de Java