Controllo null in un ciclo for avanzato


172

Qual è il modo migliore per proteggersi da null in un ciclo for in Java?

Questo sembra brutto:

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

O

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

Potrebbe non esserci altro modo. Avrebbero dovuto inserirlo nel forcostrutto stesso, se è nullo, non eseguire il ciclo?


2
Probabilmente stai meglio lanciando un NPE. nullnon è uguale a una raccolta vuota.
Tom Hawtin - affronta il

6
@GregMattes In che modo la domanda di febbraio è un duplicato della domanda di ottobre?
Val

1
Devo solo usare Collections.nonNullElementsIn (...): stackoverflow.com/a/34913556/5637185
Jeffrey Dilley,

Risposte:


228

Dovresti verificare meglio da dove ottieni quell'elenco.

Un elenco vuoto è tutto ciò che serve, perché un elenco vuoto non fallirà.

Se ottieni questo elenco da qualche altra parte e non sai se è ok o no, puoi creare un metodo di utilità e usarlo in questo modo:

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

E ovviamente safesarebbe:

public static List safe( List other ) {
    return other == null ? Collections.EMPTY_LIST : other;
}

57
Si noti che Collections.emptyList () eviterà di allocare un oggetto aggiuntivo (IIRC).
Jon Skeet,

7
@Jon: mi sono sempre chiesto, a che cosa serviva quel emptyList java.sun.com/j2se/1.5.0/docs/api/java/util/… Che cos'è IIRC?
OscarRyz,

11
IIRC = "Se ricordo bene". E sì, c'è un'istanza singleton che viene restituita per tutte le chiamate a Collections.emptyList ().
ColinD,

Questo ... in realtà non risponde alla domanda. Perché è accettata la risposta?
Christopher Wirt,

1
@ChristopherWirt perché risponde alla domanda: D
Tarik

100

Potresti potenzialmente scrivere un metodo helper che ha restituito una sequenza vuota se hai passato null:

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

Quindi utilizzare:

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

Non penso che lo farei comunque, di solito uso la tua seconda forma. In particolare, "o buttare ex" è importante - se davvero non dovrebbe essere nullo, dovresti assolutamente lanciare un'eccezione. Sai che qualcosa è andato storto, ma non conosci l'entità del danno. Interrompi presto.


3
Vorrei modificare il parametro elenco Iterable <T> in Iterable <T> iterabile, poiché non tutti gli iterabili sono un elenco.
Lombo,

Fai attenzione usando questo metodo: a causa dell'uso della classe Collections, l'uso di questo metodo implica che la tua lista sia immutabile
Tanorix

@tanorix: in che modo?
Jon Skeet,

@JonSkeet puoi vedere che emptyList () della classe Collections restituisce un elenco immutabile: docs.oracle.com/javase/8/docs/api/java/util/…, quindi se l'utente non desidera che il suo elenco sia immutabile, può sii problematico
Tanorix,

@tanorix: Ma il punto di questa domanda riguarda l' iterazione sul valore restituito. Questo non lo modifica. Ecco perché il tipo di ritorno emptyIfNullè Iterable<T>: c'è il removemetodo sfortunato attivo Iterator<T>, ma è l'unico aspetto mutevole di esso (e se hai una raccolta vuota, perché stai cercando di rimuovere qualcosa da esso?) Non è chiaro cosa tu ' stai obiettando a qui.
Jon Skeet,

29

È già il 2017 e ora puoi utilizzare Apache Commons Collections4

L'utilizzo:

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

Puoi fare lo stesso controllo null-safe con le altre classi Collection con CollectionUtils.emptyIfNull.


2
Funzionerà anche se crea un oggetto elenco non necessario. Un CollectionUtils.ifNotEmpty può essere più dettagliato ma più efficiente e più veloce. Non che importerebbe molto ...
Lawrence,

2
Nel 2017 mi aspetterei List.emptyIfNull (list1)
Dima il

3
@Lawrence, il metodo non crea nuovi oggetti elenco, utilizza Collections.emptyList()internamente, che a sua volta restituisce sempre lo stesso elenco vuoto non modificabile preallocato.
Yoory N.

Cosa succede se si chiama myobject.getCompanies (). GetAddresses () ed entrambi restituiscono un elenco ed entrambi possono essere nulli?
powder366

9

Con Java 8 Optional:

for (Object object : Optional.ofNullable(someList).orElse(Collections.emptyList())) {
    // do whatever
}

1
È più prolisso di un semplice operatore ternario someList != null ? someList : Collections.emptyList()e crea e getta immediatamente un'istanza di Optionaloggetto.
Yoory N.

2
in che modo queste linee di mostri sono più eleganti di una semplice istruzione if (someList == null). Scriviamo una domanda bancaria in una riga ...
Andreas Panagiotidis,

8

Utilizzare ArrayUtils.nullToEmptydalla commons-langlibreria per le matrici

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

Questa funzionalità esiste nella commons-langlibreria, inclusa nella maggior parte dei progetti 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;
}

Questa è la stessa della risposta data da @OscarRyz, ma per il bene del mantra DRY , credo che valga la pena notare. Vedi la pagina del progetto commons-lang . Ecco la documentazione e l' originenullToEmpty API

Voce Maven da includere commons-langnel progetto se non lo è già.

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

Sfortunatamente, commons-langnon fornisce questa funzionalità per i Listtipi. In questo caso dovresti usare un metodo di supporto come menzionato in precedenza.

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

7

Se lo si ottiene Listda una chiamata di metodo implementata, quindi non tornare null, restituire uno spazio vuoto List.

Se non riesci a modificare l'implementazione, allora sei bloccato con il nullcontrollo. Se non dovrebbe essere null, quindi getta un'eccezione.

Non sceglierei il metodo helper che restituisce un elenco vuoto perché potrebbe essere utile alcune volte, ma poi ti abitueresti a chiamarlo in ogni ciclo che potresti nascondere nascondendo alcuni bug.


4

Ho modificato la risposta sopra, quindi non è necessario eseguire il cast da Object

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

e quindi chiama semplicemente la lista di

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

Spiegazione: MyOwnObject: List<Integer>in tal caso MyOwnObject sarà integer in questo caso.


1

Un altro modo per proteggersi efficacemente da un null in un ciclo for è quello di avvolgere la tua raccolta con Google Guava Optional<T>poiché questo, si spera, rende chiara la possibilità di una raccolta effettivamente vuota poiché il cliente dovrebbe verificare se la raccolta è presente Optional.isPresent().


1

Per chiunque non sia interessato a scrivere il proprio metodo di sicurezza nulla statico è possibile utilizzare: commons-lang's org.apache.commons.lang.ObjectUtils.defaultIfNull(Object, Object). Per esempio:

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

ObjectUtils.defaultIfNull JavaDoc


Per me, questa risposta è la più elegante
Truong Nguyen,

0

Utilizzare un CollectionUtils.isEmpty(Collection coll)metodo che sia Null-safe se la raccolta specificata è vuota.

per questo import org.apache.commons.collections.CollectionUtils.

Dipendenza da Maven

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.0</version>
</dependency>

-4
for (Object object : someList) {

   // do whatever
}  throws the null pointer exception.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.