¿Cómo eliminar todos los elementos null de una matriz ArrayList o String?


Intento con un bucle como ese

// 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 mejores decisiones:

While loop, For loop and Iterator Performance Test

Author: AZ_, 2011-01-27

16 answers

Intenta:

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

Lea la API de Java . El código lanzará java.lang.UnsupportedOperationException para listas inmutables (como las creadas con Arrays.asList); vea esta respuesta para más detalles.

 331
Author: Lithium,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:38

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

tourists.removeIf(Objects::isNull);

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

 85
Author: MarcG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-19 14:21:06
list.removeAll(Collections.singleton(null));

Lanzará UnsupportedException si lo usa en matrices.asList porque te da copia inmutable para que no se pueda modificar. Ver a continuación el código. Crea copia mutable y no lanzará ninguna excepción.

public static String[] clean(final String[] v) {
    List<String> list = new ArrayList<String>(Arrays.asList(v));
    list.removeAll(Collections.singleton(null));
    return list.toArray(new String[list.size()]);
}
 44
Author: AZ_,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-13 09:24:52

No eficiente, pero corto

while(tourists.remove(null));
 18
Author: Peter Lawrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-27 17:25:26

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

ImmutableList.copyOf(Iterables.filter(tourists, Predicates.notNull()))
 17
Author: James Kojo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-30 19:54:16
 for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
      if (itr.next() == null) { itr.remove(); }
 }
 7
Author: Mat Mannion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-27 17:23:38

Hay una manera fácil de eliminar todos los valores null de collection.Debe pasar una colección que contenga null como parámetro a removeAll() method

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

yourCollection.removeAll(s1);
 3
Author: shiv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-15 09:35:19

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

Por ejemplo:

tourists.stream().filter(Objects::nonNull).collect(Collectors.toList());
 3
Author: JeffF,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-17 20:12:44

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-Flujos

 3
Author: Jad Chahine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-03 00:48:22

Esta es una manera fácil de eliminar los valores nulos predeterminados de arraylist

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

De lo contrario, el valor de cadena "null" se elimina de arraylist

       tourists.removeAll(Arrays.asList("null"));  
 2
Author: Jobin_vibes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-18 11:08:36

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

 1
Author: theblitz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-19 10:00:53

Podemos usar el iterador para el mismo para eliminar todos los valores null.

Iterator<Tourist> itr= tourists.iterator();
while(itr.hasNext()){
    if(itr.next() == null){
        itr.remove();
    }
}
 1
Author: amit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-23 11:31:17

Utilicé la interfaz stream junto con la operación stream collect y un método helper para generar una nueva lista.

tourists.stream().filter(this::isNotNull).collect(Collectors.toList());

private <T> boolean isNotNull(final T item) {
    return  item != null;
}
 1
Author: Mabi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-29 12:24:38

Pre-Java 8 debes usar:

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

Uso post-Java 8:

tourists.removeIf(Objects::isNull);

La razón aquí es la complejidad del tiempo. El problema con los arrays es que una operación de eliminación puede tardar O (n) tiempo en completarse. Realmente en Java esto es una copia de matriz de los elementos restantes que se mueven para reemplazar el lugar vacío. Muchas otras soluciones ofrecidas aquí desencadenarán este problema. El primero es técnicamente O (n * m) donde m es 1 porque es un null singleton: so O(n)

Debe eliminar todo el singleton, internamente hace un batchRemove () que tiene una posición de lectura y una posición de escritura. E itera la lista. Cuando llega a un null, simplemente itera la posición de lectura por 1. Cuando son iguales pasa, cuando son diferentes sigue moviéndose copiando los valores. Luego al final se recorta a medida.

Efectivamente hace esto internamente:

public static <E> void removeNulls(ArrayList<E> 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();
    }
}

Que se puede ver explícitamente es una operación O(n).

Lo único que podría ser más rápido es si iteró la lista desde ambos extremos, y cuando encontró un null, estableció su valor igual al valor que encontró al final, y decrementó ese valor. E iterado hasta que los dos valores coincidieron. Arruinaría el orden, pero reduciría enormemente el número de valores se establece vs que dejaron solo. Que es un buen método para saber, pero no ayudará mucho aquí como .set() es básicamente gratis, pero esa forma de eliminar es una herramienta útil para tu cinturón.


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

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

ArrayList.this.remove(lastRet);

Que es de nuevo la operación O(n) dentro de la eliminación. Hace un Sistema.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 repetimos la lista. Reiteramos toda la lista, cada vez que coincidimos con el null. Luego hacemos n / 2 (promedio) operaciones para hacer el Sistema.arraycopy () para realizar la eliminación. Podrías literalmente, ordene toda la colección entre elementos con valores y elementos con valores nulos y recorte el final 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, teoría y práctica son la misma cosa; en la práctica no lo son.

 1
Author: Tatarize,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-28 03:21:40

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

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

El flujo paralelo hará uso de los procesadores disponibles y acelerará el proceso para listas de tamaño razonable. Siempre es recomendable hacer benchmark antes de usar streams.

 0
Author: i_am_zero,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-15 15:30:44

Similar a la respuesta de @Lithium pero no arroja un error de "La lista no puede contener el tipo null":

   list.removeAll(Collections.<T>singleton(null));
 0
Author: Hannah Louisa Carney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-05 05:53:49