Java Language
Liza
Buscar..
Introducción
Una lista es una colección ordenada de valores. En Java, las listas son parte de Java Collections Framework . Las listas implementan la interfaz java.util.List
, que extiende java.util.Collection
.
Sintaxis
- ls.add (elemento E); // Agrega un elemento
- ls.remove (elemento E); // Elimina un elemento
- para (elemento E: ls) {} // itera sobre cada elemento
- ls.toArray (nueva cadena [ls.length]); // Convierte una lista de cadenas a una matriz de cadenas
- ls.get (índice int); // Devuelve el elemento en el índice especificado.
- ls.set (índice int, elemento E); // Reemplaza el elemento en una posición especificada.
- ls.isEmpty (); // Devuelve verdadero si la matriz no contiene elementos, de lo contrario, devuelve falso.
- ls.indexOf (Objeto o); // Devuelve el índice de la primera ubicación del elemento especificado o, o, si no está presente, devuelve -1.
- ls.lastIndexOf (Objeto o); // Devuelve el índice de la última ubicación del elemento especificado o, o, si no está presente, devuelve -1.
- ls.size (); // Devuelve el número de elementos en la Lista.
Observaciones
Una lista es un objeto que almacena una colección ordenada de valores. "Ordenado" significa que los valores se almacenan en un orden particular: un elemento aparece primero, otro ocupa el segundo lugar, etc. Los valores individuales son comúnmente llamados "elementos". Las listas de Java suelen proporcionar estas características:
- Las listas pueden contener cero o más elementos.
- Las listas pueden contener valores duplicados. En otras palabras, un elemento se puede insertar en una lista más de una vez.
- Las listas almacenan sus elementos en un orden particular, lo que significa que un elemento viene primero, uno viene a continuación, y así sucesivamente.
- Cada elemento tiene un índice que indica su posición dentro de la lista. El primer elemento tiene índice 0, el siguiente tiene índice 1 y así sucesivamente.
- Las listas permiten la inserción de elementos al principio, al final o en cualquier índice dentro de la lista.
- Comprobar si una lista contiene un valor particular generalmente significa examinar cada elemento de la lista. Esto significa que el tiempo para realizar esta comprobación es O (n) , proporcional al tamaño de la lista.
Agregar un valor a una lista en algún punto que no sea el final moverá todos los siguientes elementos "hacia abajo" o "hacia la derecha". En otras palabras, agregar un elemento en el índice n mueve el elemento que solía estar en el índice n al índice n + 1 , y así sucesivamente. Por ejemplo:
List<String> list = new ArrayList<>();
list.add("world");
System.out.println(list.indexOf("world")); // Prints "0"
// Inserting a new value at index 0 moves "world" to index 1
list.add(0, "Hello");
System.out.println(list.indexOf("world")); // Prints "1"
System.out.println(list.indexOf("Hello")); // Prints "0"
Ordenar una lista genérica
La clase Collections
ofrece dos métodos estáticos estándar para ordenar una lista:
-
sort(List<T> list)
aplicable a listas dondeT extends Comparable<? super T>
, y -
sort(List<T> list, Comparator<? super T> c)
aplicable a listas de cualquier tipo.
Aplicar lo anterior requiere modificar la clase de elementos de lista que se están ordenando, lo que no siempre es posible. También puede ser indeseable ya que, si bien proporciona la clasificación predeterminada, es posible que se requieran otras órdenes de clasificación en diferentes circunstancias, o la clasificación es una tarea única.
Considere que tenemos la tarea de ordenar los objetos que son instancias de la siguiente clase:
public class User {
public final Long id;
public final String username;
public User(Long id, String username) {
this.id = id;
this.username = username;
}
@Override
public String toString() {
return String.format("%s:%d", username, id);
}
}
Para utilizar Collections.sort(List<User> list)
necesitamos modificar la clase de User
para implementar la interfaz Comparable
. Por ejemplo
public class User implements Comparable<User> {
public final Long id;
public final String username;
public User(Long id, String username) {
this.id = id;
this.username = username;
}
@Override
public String toString() {
return String.format("%s:%d", username, id);
}
@Override
/** The natural ordering for 'User' objects is by the 'id' field. */
public int compareTo(User o) {
return id.compareTo(o.id);
}
}
(Aparte: muchas clases Java estándar como String
, Long
, Integer
implementan la interfaz Comparable
. Esto hace que las listas de esos elementos se puedan ordenar de forma predeterminada y simplifica la implementación de compare
o compareTo
en otras clases).
Con la modificación anterior, podemos ordenar fácilmente una lista de objetos de User
según el orden natural de las clases. (En este caso, hemos definido que se ordenen según los valores de id
). Por ejemplo:
List<User> users = Lists.newArrayList(
new User(33L, "A"),
new User(25L, "B"),
new User(28L, ""));
Collections.sort(users);
System.out.print(users);
// [B:25, C:28, A:33]
Sin embargo, supongamos que queremos ordenar los objetos de User
por name
lugar de por id
. Alternativamente, supongamos que no pudimos cambiar la clase para que sea implementable como Comparable
.
Aquí es donde el método de sort
con el argumento del Comparator
es útil:
Collections.sort(users, new Comparator<User>() {
@Override
/* Order two 'User' objects based on their names. */
public int compare(User left, User right) {
return left.username.compareTo(right.username);
}
});
System.out.print(users);
// [A:33, B:25, C:28]
En Java 8 puedes usar un lambda en lugar de una clase anónima. Este último se reduce a una sola línea:
Collections.sort(users, (l, r) -> l.username.compareTo(r.username));
Además, Java 8 agrega un método de sort
predeterminado en la interfaz de List
, lo que simplifica la clasificación aún más.
users.sort((l, r) -> l.username.compareTo(r.username))
Creando una lista
Dando a tu lista un tipo
Para crear una lista necesita un tipo (cualquier clase, por ejemplo, String
). Este es el tipo de su List
. La List
solo almacenará objetos del tipo especificado. Por ejemplo:
List<String> strings;
Puede almacenar "string1"
, "hello world!"
, "goodbye"
, etc., pero no puede almacenar 9.2
, sin embargo:
List<Double> doubles;
Puede almacenar 9.2
, pero no "hello world!"
.
Inicializando tu lista
Si intentas agregar algo a las listas anteriores, obtendrás una NullPointerException, ¡porque las strings
y los doubles
nulos iguales!
Hay dos formas de inicializar una lista:
Opción 1: usar una clase que implemente lista
List
es una interfaz, lo que significa que no tiene un constructor, sino métodos que una clase debe reemplazar. ArrayList
es el más comúnmente utilizado List
, aunque LinkedList
también es común. Así que inicializamos nuestra lista de esta manera:
List<String> strings = new ArrayList<String>();
o
List<String> strings = new LinkedList<String>();
A partir de Java SE 7, puede utilizar un operador de diamante :
List<String> strings = new ArrayList<>();
o
List<String> strings = new LinkedList<>();
Opción 2: usar la clase Colecciones
La clase Collections
proporciona dos métodos útiles para crear listas sin una variable de List
:
-
emptyList()
: devuelve una lista vacía. -
singletonList(T)
: crea una lista de tipo T y agrega el elemento especificado.
Y un método que utiliza una List
existente para completar los datos:
-
addAll(L, T...)
: agrega todos los elementos especificados a la lista pasada como primer parámetro.
Ejemplos:
import java.util.List; import java.util.Collections; List<Integer> l = Collections.emptyList(); List<Integer> l1 = Collections.singletonList(42); Collections.addAll(l1, 1, 2, 3);
Operaciones de acceso posicional
La API de lista tiene ocho métodos para las operaciones de acceso posicional:
-
add(T type)
-
add(int index, T type)
-
remove(Object o)
-
remove(int index)
-
get(int index)
-
set(int index, E element)
-
int indexOf(Object o)
-
int lastIndexOf(Object o)
Entonces, si tenemos una lista:
List<String> strings = new ArrayList<String>();
Y queríamos añadir las cuerdas "¡Hola mundo!" y "adiós mundo!" Para ello, lo haríamos como tal:
strings.add("Hello world!");
strings.add("Goodbye world!");
Y nuestra lista contendría los dos elementos. Ahora digamos que queríamos agregar "¡Programa empezando!" al frente de la lista. Haríamos esto así:
strings.add(0, "Program starting!");
NOTA: El primer elemento es 0.
Ahora, si quisiéramos eliminar el "¡Adiós mundo!" Línea, podríamos hacerlo así:
strings.remove("Goodbye world!");
Y si quisiéramos eliminar la primera línea (que en este caso sería "¡Programa empezando!", Podríamos hacerlo así:
strings.remove(0);
Nota:
Agregar y eliminar elementos de la lista modifica la lista, y esto puede llevar a una
ConcurrentModificationException
si la lista se está iterando simultáneamente.La adición y eliminación de elementos puede ser
O(1)
uO(N)
según la clase de lista, el método utilizado y si está agregando / eliminando un elemento al inicio, al final o en medio de la lista.
Para recuperar un elemento de la lista en una posición específica, puede utilizar el E get(int index);
Método de la lista API. Por ejemplo:
strings.get(0);
Volverá el primer elemento de la lista.
Puede reemplazar cualquier elemento en una posición específica usando el set(int index, E element);
. Por ejemplo:
strings.set(0,"This is a replacement");
Esto establecerá la Cadena "Esto es un reemplazo" como el primer elemento de la lista.
Nota: El método de configuración sobrescribirá el elemento en la posición 0. No agregará la nueva Cadena en la posición 0 y empujará la antigua a la posición 1.
El int indexOf(Object o);
devuelve la posición de la primera aparición del objeto pasado como argumento. Si no hay apariciones del objeto en la lista, se devuelve el valor -1. Continuando con el ejemplo anterior si llama:
strings.indexOf("This is a replacement")
se espera que se devuelva el 0 cuando configuramos la Cadena "Esto es un reemplazo" en la posición 0 de nuestra lista. En caso de que haya más de una aparición en la lista cuando int indexOf(Object o);
Se llama entonces como se mencionó se devolverá el índice de la primera aparición. Al llamar a int lastIndexOf(Object o)
, puede recuperar el índice de la última aparición en la lista. Así que si agregamos otro "Este es un reemplazo":
strings.add("This is a replacement");
strings.lastIndexOf("This is a replacement");
Esta vez se devolverá el 1 y no el 0;
Iterando sobre elementos en una lista
Para el ejemplo, digamos que tenemos una Lista de tipo String que contiene cuatro elementos: "hola", "cómo", "son", "usted?"
La mejor manera de iterar sobre cada elemento es usando un bucle para cada uno:
public void printEachElement(List<String> list){
for(String s : list){
System.out.println(s);
}
}
Que imprimiría:
hello,
how
are
you?
Para imprimirlos todos en la misma línea, puede usar un StringBuilder:
public void printAsLine(List<String> list){
StringBuilder builder = new StringBuilder();
for(String s : list){
builder.append(s);
}
System.out.println(builder.toString());
}
Se imprimirá:
hello, how are you?
Alternativamente, puede usar la indexación de elementos (como se describe en Acceso a un elemento en el índice de ArrayList ) para iterar una lista. Advertencia: este enfoque es ineficiente para las listas enlazadas.
Eliminar elementos de la lista B que están presentes en la lista A
Supongamos que tiene 2 listas A y B, y desea eliminar de B todos los elementos que tiene en A, el método en este caso es
List.removeAll(Collection c);
#Ejemplo:
public static void main(String[] args) {
List<Integer> numbersA = new ArrayList<>();
List<Integer> numbersB = new ArrayList<>();
numbersA.addAll(Arrays.asList(new Integer[] { 1, 3, 4, 7, 5, 2 }));
numbersB.addAll(Arrays.asList(new Integer[] { 13, 32, 533, 3, 4, 2 }));
System.out.println("A: " + numbersA);
System.out.println("B: " + numbersB);
numbersB.removeAll(numbersA);
System.out.println("B cleared: " + numbersB);
}
esto imprimirá
A: [1, 3, 4, 7, 5, 2]
B: [13, 32, 533, 3, 4, 2]
B despejado: [13, 32, 533]
Encontrando elementos comunes entre 2 listas.
Supongamos que tiene dos listas: A y B, y necesita encontrar los elementos que existen en ambas listas.
Puede hacerlo simplemente invocando el método List.retainAll()
.
Ejemplo:
public static void main(String[] args) {
List<Integer> numbersA = new ArrayList<>();
List<Integer> numbersB = new ArrayList<>();
numbersA.addAll(Arrays.asList(new Integer[] { 1, 3, 4, 7, 5, 2 }));
numbersB.addAll(Arrays.asList(new Integer[] { 13, 32, 533, 3, 4, 2 }));
System.out.println("A: " + numbersA);
System.out.println("B: " + numbersB);
List<Integer> numbersC = new ArrayList<>();
numbersC.addAll(numbersA);
numbersC.retainAll(numbersB);
System.out.println("List A : " + numbersA);
System.out.println("List B : " + numbersB);
System.out.println("Common elements between A and B: " + numbersC);
}
Convertir una lista de enteros en una lista de cadenas
List<Integer> nums = Arrays.asList(1, 2, 3);
List<String> strings = nums.stream()
.map(Object::toString)
.collect(Collectors.toList());
Es decir:
- Crear un flujo de la lista
- Mapea cada elemento usando
Object::toString
- Recopile los valores de
String
en unaList
usandoCollectors.toList()
Creación, adición y eliminación de elementos de un ArrayList
ArrayList
es una de las estructuras de datos incorporadas en Java. Es una matriz dinámica (donde el tamaño de la estructura de datos no necesita declararse primero) para almacenar elementos (Objetos).
Extiende la clase AbstractList
e implementa la interfaz de List
. Un ArrayList
puede contener elementos duplicados donde mantiene el orden de inserción. Se debe tener en cuenta que la clase ArrayList
no está sincronizada, por lo que se debe tener cuidado al manejar la concurrencia con ArrayList
. ArrayList
permite el acceso aleatorio porque la matriz funciona en la base del índice. La manipulación es lenta en ArrayList
debido a los cambios que ocurren a menudo cuando se elimina un elemento de la lista de arreglos.
Un ArrayList
se puede crear de la siguiente manera:
List<T> myArrayList = new ArrayList<>();
Donde T
( Genéricos ) es el tipo que se almacenará dentro de ArrayList
.
El tipo de ArrayList
puede ser cualquier Objeto. El tipo no puede ser un tipo primitivo (en su lugar, use sus clases de envoltorio ).
Para agregar un elemento al ArrayList
, use el método add()
:
myArrayList.add(element);
O para agregar un artículo a un determinado índice:
myArrayList.add(index, element); //index of the element should be an int (starting from 0)
Para eliminar un elemento de ArrayList
, use el método remove()
:
myArrayList.remove(element);
O bien, para eliminar un elemento de un determinado índice:
myArrayList.remove(index); //index of the element should be an int (starting from 0)
Sustitución in situ de un elemento de lista
Este ejemplo se trata de reemplazar un elemento de la List
mientras se asegura que el elemento de reemplazo esté en la misma posición que el elemento que se reemplaza.
Esto se puede hacer usando estos métodos:
- conjunto (índice int, tipo T)
- int indexOf (tipo T)
Considere una ArrayList
contenga los elementos "¡Programa empezando!", "¡Hola mundo!" y "adiós mundo!"
List<String> strings = new ArrayList<String>();
strings.add("Program starting!");
strings.add("Hello world!");
strings.add("Goodbye world!");
Si conocemos el índice del elemento que queremos reemplazar, simplemente podemos usar set
siguiente manera:
strings.set(1, "Hi world");
Si no conocemos el índice, podemos buscarlo primero. Por ejemplo:
int pos = strings.indexOf("Goodbye world!");
if (pos >= 0) {
strings.set(pos, "Goodbye cruel world!");
}
Notas:
- La operación
set
no generará unaConcurrentModificationException
. - La operación
set
es rápida (O(1)
) paraArrayList
pero lenta (O(N)
) para una listaLinkedList
. - Una búsqueda
indexOf
en unArrayList
oLinkedList
es lenta (O(N)
).
Haciendo una lista no modificable
La clase Colecciones proporciona una manera de hacer que una lista no sea modificable:
List<String> ls = new ArrayList<String>();
List<String> unmodifiableList = Collections.unmodifiableList(ls);
Si desea una lista no modificable con un elemento, puede utilizar:
List<String> unmodifiableList = Collections.singletonList("Only string in the list");
Mover objetos alrededor de la lista
La clase Colecciones le permite mover objetos en la lista usando varios métodos (ls es la Lista):
Invertir una lista:
Collections.reverse(ls);
Posiciones rotativas de elementos en una lista.
El método de rotación requiere un argumento entero. Este es el número de puntos para moverlo a lo largo de la línea. Un ejemplo de esto es a continuación:
List<String> ls = new ArrayList<String>();
ls.add(" how");
ls.add(" are");
ls.add(" you?");
ls.add("hello,");
Collections.rotate(ls, 1);
for(String line : ls) System.out.print(line);
System.out.println();
Esto imprimirá "hola, ¿cómo estás?"
Mezclando elementos alrededor de una lista
Usando la misma lista anterior, podemos barajar los elementos en una lista:
Collections.shuffle(ls);
También podemos darle un objeto java.util.Random que utiliza para colocar objetos aleatoriamente en puntos:
Random random = new Random(12);
Collections.shuffle(ls, random);
Clases implementando Lista - Pros y Contras
La interfaz de List
está implementada por diferentes clases. Cada uno de ellos tiene su propio camino para implementarlo con diferentes estrategias y proporcionar diferentes pros y contras.
Clases implementando la lista
Estas son todas las clases public
en Java SE 8 que implementan la interfaz java.util.List
:
- Clases abstractas:
- Lista abstracta
- AbstractSequentialList
- Clases de concreto:
- Lista de arreglo
- Lista de atributos
- CopyOnWriteArrayList
- Lista enlazada
- Lista de roles
- RoleUnresolvedList
- Apilar
- Vector
Pros y contras de cada implementación en términos de complejidad de tiempo
Lista de arreglo
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
ArrayList es una implementación de matriz de tamaño variable de la interfaz de lista. Al almacenar la lista en una matriz, ArrayList proporciona métodos (además de los métodos que implementan la interfaz de la Lista ) para manipular el tamaño de la matriz.
Inicializar ArrayList de entero con tamaño 100
List<Integer> myList = new ArrayList<Integer>(100); // Constructs an empty list with the specified initial capacity.
- PROS:
Las operaciones size, isEmpty, get , set , iterator y listIterator se ejecutan en tiempo constante. Por lo tanto, obtener y configurar cada elemento de la Lista tiene el mismo costo de tiempo :
int e1 = myList.get(0); // \
int e2 = myList.get(10); // | => All the same constant cost => O(1)
myList.set(2,10); // /
- CONTRAS:
La implementación con una matriz (estructura estática) que agrega elementos sobre el tamaño de la matriz tiene un gran costo debido al hecho de que es necesario realizar una nueva asignación para toda la matriz. Sin embargo, a partir de la documentación :
La operación de adición se ejecuta en tiempo constante amortizado, es decir, agregar n elementos requiere tiempo O (n)
La eliminación de un elemento requiere O (n) tiempo.
Lista de atributos
En venir
CopyOnWriteArrayList
En venir
Lista enlazada
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, Serializable
LinkedList se implementa mediante una lista doblemente enlazada, una estructura de datos vinculados que consiste en un conjunto de registros vinculados secuencialmente llamados nodos.
Iitialize LinkedList of Integer
List<Integer> myList = new LinkedList<Integer>(); // Constructs an empty list.
- PROS:
Agregar o eliminar un elemento al principio de la lista o al final tiene un tiempo constante.
myList.add(10); // \
myList.add(0,2); // | => constant time => O(1)
myList.remove(); // /
- CONTRA: De la documentación :
Las operaciones que indizan en la lista recorrerán la lista desde el principio o el final, lo que esté más cerca del índice especificado.
Operaciones como:
myList.get(10); // \
myList.add(11,25); // | => worst case done in O(n/2)
myList.set(15,35); // /
Lista de roles
En venir
RoleUnresolvedList
En venir
Apilar
En venir
Vector
En venir