¿Cómo eliminar todos los elementos nulos de ArrayList o String Array?

Intento con un bucle así

// ArrayList tourists for (Tourist t : tourists) { if (t != null) { t.setId(idForm); } } 

Pero no es agradable. ¿Alguien puede sugerirme una mejor solución?


Algunos puntos de referencia útiles para tomar una mejor decisión:

While loop, For loop y Iterator Performance Test

Tratar:

 tourists.removeAll(Collections.singleton(null)); 

Lee la API de Java El código arrojará java.lang.UnsupportedOperationException para listas inmutables (como creado con Arrays.asList ); ver esta respuesta para más detalles.

A partir de 2015, esta es la mejor manera (Java 8):

 tourists.removeIf(Objects::isNull); 

Nota: Este código arrojará java.lang.UnsupportedOperationException para listas de tamaño fijo (como las creadas con Arrays.asList), incluidas las listas inmutables.

 list.removeAll(Collections.singleton(null)); 

Lanzará UnsupportedException si lo usa en Arrays.asList porque le da una copia inmutable por lo que no se puede modificar. Vea debajo el código. Crea una copia mutable y no lanzará ninguna excepción.

 public static String[] clean(final String[] v) { List list = new ArrayList(Arrays.asList(v)); list.removeAll(Collections.singleton(null)); return list.toArray(new String[list.size()]); } 

No eficiente, pero corto

 while(tourists.remove(null)); 

Si prefiere objetos de datos inmutables, o si simplemente no desea ser destructivo para la lista de entrada, puede usar los predicados de Guava.

 ImmutableList.copyOf(Iterables.filter(tourists, Predicates.notNull())) 
  for (Iterator itr = tourists.iterator(); itr.hasNext();) { if (itr.next() == null) { itr.remove(); } } 

Hay una manera fácil de eliminar todos los valores null de la collection . removeAll() pasar una colección que contiene null como parámetro para removeAll() método removeAll()

 List s1=new ArrayList(); s1.add(null); yourCollection.removeAll(s1); 

La clase Objects tiene un Predicate nonNull que se puede usar con filter .

Por ejemplo:

 tourists.stream().filter(Objects::nonNull).collect(Collectors.toList()); 

Usando Java 8, puedes hacer esto usando stream() y filter()

 tourists = tourists.stream().filter(t -> t != null).collect(Collectors.toList()) 

o

 tourists = tourists.stream().filter(Objects::nonNull).collect(Collectors.toList()) 

Para más información: Java 8 – Streams

Esta es una manera fácil de eliminar los valores nulos predeterminados de la lista de arrays

  tourists.removeAll(Arrays.asList(null)); 

de lo contrario, valor de cadena “nulo” eliminar de la lista de arrays

  tourists.removeAll(Arrays.asList("null")); 

Jugué con esto y descubrí que trimToSize () parece funcionar. Estoy trabajando en la plataforma Android, por lo que podría ser diferente.

Podemos usar iterator para lo mismo para eliminar todos los valores nulos.

 Iterator itr= tourists.iterator(); while(itr.hasNext()){ if(itr.next() == null){ itr.remove(); } } 

Usé la interfaz de flujo junto con la operación de recostackción de flujo y un método de ayuda para generar una nueva lista.

 tourists.stream().filter(this::isNotNull).collect(Collectors.toList()); private  boolean isNotNull(final T item) { return item != null; } 

Pre-Java 8 deberías usar:

 tourists.removeAll(Collections.singleton(null)); 

Uso posterior a Java 8:

 tourists.removeIf(Objects::isNull); 

La razón aquí es la complejidad del tiempo. El problema con las matrices es que una operación de eliminación puede tomar O (n) tiempo para completarse. Realmente en Java, esta es una copia de la matriz de los elementos restantes que se mueven para reemplazar la mancha vacía. Muchas otras soluciones que se ofrecen aquí desencadenarán este problema. El primero es técnicamente O (n * m) donde m es 1 porque es un nulo singleton: entonces O (n)

Debe eliminar Todo del singleton, internamente realiza un batchRemove () que tiene una posición de lectura y una posición de escritura. Y repite la lista. Cuando llega a un nulo, simplemente itera la posición de lectura en 1. Cuando pasan lo mismo, cuando son diferentes se mueve a lo largo de la copia de los valores. Luego, al final, se ajusta a medida.

Efectivamente lo hace internamente:

 public static  void removeNulls(ArrayList list) { int size = list.size(); int read = 0; int write = 0; for (; read < size; read++) { E element = list.get(read); if (element == null) continue; if (read != write) list.set(write, element); write++; } if (write != size) { list.subList(write, size).clear(); } } 

Lo que puedes ver explícitamente es una operación O (n).

Lo único que podría ser más rápido es si repitió la lista desde ambos extremos, y cuando encontró un valor nulo, establece su valor igual al valor que encontró al final, y disminuyó ese valor. Y se repitió hasta que los dos valores coincidieron. Perjudicas el orden, pero reduciría enormemente la cantidad de valores que estableces frente a los que dejaste solos. Lo cual es un buen método para saber pero no ayudará mucho porque .set () es básicamente gratis, pero esa forma de eliminar es una herramienta útil para tu cinturón.


 for (Iterator itr = tourists.iterator(); itr.hasNext();) { if (itr.next() == null) { itr.remove(); } } 

Si bien esto parece bastante razonable, el .remove () en el iterador llama internamente:

 ArrayList.this.remove(lastRet); 

Que es nuevamente la operación O (n) dentro del removedor. Hace una System.arraycopy () que de nuevo no es lo que quieres, si te importa la velocidad. Esto lo hace n ^ 2.

También hay:

 while(tourists.remove(null)); 

Que es O (m * n ^ 2). Aquí no solo iteramos la lista. Reiteramos toda la lista, cada vez que hacemos coincidir el nulo. Luego hacemos n / 2 (promedio) de operaciones para hacer el System.arraycopy () para realizar la eliminación. Podría literalmente clasificar la colección completa entre elementos con valores y elementos con valores nulos y recortar la terminación en menos tiempo. De hecho, eso es cierto para todos los rotos. Al menos en teoría, el sistema real.arraycopy no es realmente una operación N en la práctica. En teoría, la teoría y la práctica son la misma cosa; en la práctica, no lo son.

Usando Java 8 esto se puede realizar de varias maneras usando secuencias, flujos paralelos y método removeIf :

 List stringList = new ArrayList<>(Arrays.asList(null, "A", "B", null, "C", null)); List listWithoutNulls1 = stringList.stream() .filter(Objects::nonNull) .collect(Collectors.toList()); //[A,B,C] List listWithoutNulls2 = stringList.parallelStream() .filter(Objects::nonNull) .collect(Collectors.toList()); //[A,B,C] stringList.removeIf(Objects::isNull); //[A,B,C] 

La transmisión en paralelo hará uso de los procesadores disponibles y acelerará el proceso para listas de tamaño razonable. Siempre es recomendable hacer una evaluación comparativa antes de usar transmisiones.

Similar a la respuesta @Lithium, pero no arroja un error “La lista no puede contener el tipo nulo”:

  list.removeAll(Collections.singleton(null)); 
    Intereting Posts