Comprobación nula en un bucle for mejorado

172

¿Cuál es la mejor manera de protegerse contra nulo en un bucle for en Java?

Esto parece feo:

if (someList != null) {
    for (Object object : someList) {
        // do whatever
    }
}

O

if (someList == null) {
    return; // Or throw ex
}
for (Object object : someList) {
    // do whatever
}

Puede que no haya otra forma. ¿Deberían haberlo puesto en la forconstrucción en sí, si es nulo, entonces no ejecute el ciclo?

fastcodejava
fuente
2
Probablemente sea mejor tirar un NPE. nullNo es lo mismo que una colección vacía.
Tom Hawtin - tackline
66
@GregMattes ¿Cómo la pregunta de febrero es un duplicado de la pregunta de octubre?
Val
1
Solo necesito usar Collections.nonNullElementsIn (...): stackoverflow.com/a/34913556/5637185
Jeffrey Dilley

Respuestas:

228

Debería verificar mejor de dónde obtiene esa lista.

Una lista vacía es todo lo que necesita, porque una lista vacía no fallará.

Si obtiene esta lista de otro lugar y no sabe si está bien o no, podría crear un método de utilidad y usarlo así:

for( Object o : safe( list ) ) {
   // do whatever 
 }

Y por supuesto safesería:

public static List safe( List other ) {
    return other == null ? Collections.EMPTY_LIST : other;
}
OscarRyz
fuente
57
Tenga en cuenta que Collections.emptyList () evitará asignar un objeto adicional (IIRC).
Jon Skeet
77
@ Jon: Siempre me he preguntado, ¿de qué sirve emptyList java.sun.com/j2se/1.5.0/docs/api/java/util/… ¿Qué es el IIRC?
OscarRyz
11
IIRC = "Si recuerdo correctamente". Y sí, hay una instancia singleton que se devuelve para todas las llamadas a Collections.emptyList ().
ColinD
Esto ... en realidad no responde la pregunta. ¿Por qué se acepta la respuesta?
Christopher Wirt
1
@ChristopherWirt porque responde la pregunta: D
Tarik
100

Potencialmente, podría escribir un método auxiliar que devuelva una secuencia vacía si pasa nulo:

public static <T> Iterable<T> emptyIfNull(Iterable<T> iterable) {
    return iterable == null ? Collections.<T>emptyList() : iterable;
}

Luego use:

for (Object object : emptyIfNull(someList)) {
}

Sin embargo, no creo que realmente haga eso, generalmente usaría su segunda forma. En particular, "o throw ex" es importante: si realmente no debería ser nulo, definitivamente debe lanzar una excepción. Sabes que algo salió mal, pero no sabes el alcance del daño. Abortar temprano.

Jon Skeet
fuente
3
Cambiaría el parámetro de lista Iterable <T> a Iterable <T> iterable, ya que no todos los iterables son una lista.
Lombo
Tenga cuidado al usar este método: debido al uso de la clase Colecciones, el uso de este método implica que su lista sea inmutable
Tanorix
@tanorix: ¿De qué manera?
Jon Skeet
@JonSkeet puede ver que emptyList () de la clase Collections devuelve una lista inmutable: docs.oracle.com/javase/8/docs/api/java/util/… así que si el usuario no quiere que su lista sea inmutable, puede ser problemático
Tanorix
@tanorix: Pero el punto de esta pregunta es sobre iterar sobre el valor devuelto. Eso no lo modifica. Es por eso que el tipo de retorno emptyIfNulles Iterable<T>: hay un removemétodo desafortunado Iterator<T>, pero ese es el único aspecto mutable del mismo (y si tiene una colección vacía, ¿por qué está tratando de eliminar algo de ella?) No está claro qué es ' re objetando aquí.
Jon Skeet
29

Ya es 2017, y ahora puedes usar Apache Commons Collections4

El uso:

for(Object obj : ListUtils.emptyIfNull(list1)){
    // Do your stuff
}

Puede hacer la misma comprobación de seguridad nula para otras clases de colección con CollectionUtils.emptyIfNull.

Fred Pym
fuente
2
Funcionará aunque crea un objeto de lista innecesario. Una CollectionUtils.ifNotEmpty puede ser más detallada pero más eficiente y más rápida. No es que importe mucho ...
Lawrence
2
En 2017 esperaría List.emptyIfNull (list1)
Dima
3
@Lawrence, el método no crea nuevos objetos de lista, los usa Collections.emptyList()internamente, lo que a su vez siempre devuelve la misma lista vacía no modificable preasignada.
Yoory N.
¿Qué sucede si llama a myobject.getCompanies (). GetAddresses () y ambos devuelven una Lista y ambos pueden ser nulos?
polvo366
9

Con Java 8 Optional:

for (Object object : Optional.ofNullable(someList).orElse(Collections.emptyList())) {
    // do whatever
}
holmis83
fuente
1
Es más detallado que un simple operador ternario, someList != null ? someList : Collections.emptyList()y también crea e inmediatamente arroja una instancia de Optionalobjeto.
Yoory N.
2
¿Cómo son estas líneas de monstruo más elegantes que una simple instrucción if (someList == null)? Escribamos una solicitud bancaria en una línea ...
Andreas Panagiotidis
8

Uso ArrayUtils.nullToEmptyde la commons-langbiblioteca para matrices

for( Object o : ArrayUtils.nullToEmpty(list) ) {
   // do whatever 
}

Esta funcionalidad existe en la commons-langbiblioteca, que se incluye en la mayoría de los proyectos Java.

// ArrayUtils.nullToEmpty source code 
public static Object[] nullToEmpty(final Object[] array) {
    if (isEmpty(array)) {
        return EMPTY_OBJECT_ARRAY;
    }
    return array;
}

// ArrayUtils.isEmpty source code
public static boolean isEmpty(final Object[] array) {
    return array == null || array.length == 0;
}

Esto es lo mismo que la respuesta dada por @OscarRyz, pero por el bien del mantra DRY , creo que vale la pena señalar. Vea la página del proyecto commons-lang . Aquí está la documentación y la fuente de la nullToEmptyAPI

Entrada de Maven para incluir commons-langen su proyecto si aún no lo está.

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
</dependency>

Desafortunadamente, commons-langno proporciona esta funcionalidad para los Listtipos. En este caso, tendría que usar un método auxiliar como se mencionó anteriormente.

public static <E> List<E> nullToEmpty(List<E> list)
{
    if(list == null || list.isEmpty())
    {
        return Collections.emptyList();
    }
    return list;
}
sdc
fuente
7

Si obtiene eso Listde una llamada a un método que implementa, no devuelva null, devuelva un vacío List.

Si no puede cambiar la implementación, entonces está atascado con la nullverificación. Si no debería ser así null, lanza una excepción.

No elegiría el método auxiliar que devuelve una lista vacía porque puede ser útil algunas veces, pero luego te acostumbrarías a llamarlo en cada bucle que hagas, posiblemente ocultando algunos errores.

Lombo
fuente
4

He modificado la respuesta anterior, por lo que no necesita lanzar desde Object

public static <T> List<T> safeClient( List<T> other ) {
            return other == null ? Collections.EMPTY_LIST : other;
}

y luego simplemente llame a la Lista por

for (MyOwnObject ownObject : safeClient(someList)) {
    // do whatever
}

Explicación: MyOwnObject: si es List<Integer>así, MyOwnObject será Integer en este caso.

Haris Iltifat
fuente
1

Otra forma de protegerse eficazmente contra un nulo en un bucle for es envolver su colección con Google Guava's Optional<T>ya que esto, se espera, deja en claro la posibilidad de una colección efectivamente vacía, ya que se esperaría que el cliente verifique si la colección está presente Optional.isPresent().

Nico de Wet
fuente
1

Para cualquiera que no esté interesado en escribir su propio método de seguridad nulo estático, puede usar: commons-lang's org.apache.commons.lang.ObjectUtils.defaultIfNull(Object, Object). Por ejemplo:

    for (final String item : 
    (List<String>)ObjectUtils.defaultIfNull(items, Collections.emptyList())) { ... }

ObjectUtils.defaultIfNull JavaDoc

Jacob Briscoe
fuente
Para mí, esta respuesta es la más elegante
Truong Nguyen
0

Use, CollectionUtils.isEmpty(Collection coll)método que es Null-safe check si la colección especificada está vacía.

para esto import org.apache.commons.collections.CollectionUtils.

Dependencia Maven

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.0</version>
</dependency>
Swadeshi
fuente
-4
for (Object object : someList) {

   // do whatever
}  throws the null pointer exception.
usuario6315386
fuente