Null sprawdza w rozszerzonej pętli for

172

Jaki jest najlepszy sposób ochrony przed zerami w pętli for w Javie?

To wydaje się brzydkie:

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

Lub

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

Inaczej może nie być. Czy powinni umieścić go w forsamej konstrukcji, jeśli jest zerowy, to nie uruchamiaj pętli?

fastcodejava
źródło
2
Prawdopodobnie lepiej jest wyrzucić NPE. nullto nie to samo, co pusta kolekcja.
Tom Hawtin - tackline
6
@GregMattes W jaki sposób pytanie z lutego jest duplikatem pytania z października?
Val
1
Wystarczy użyć Collections.nonNullElementsIn (...): stackoverflow.com/a/34913556/5637185
Jeffrey Dilley

Odpowiedzi:

227

Powinieneś lepiej sprawdzić, skąd masz tę listę.

Potrzebujesz tylko pustej listy, ponieważ pusta lista nie zawiedzie.

Jeśli otrzymasz tę listę z innego miejsca i nie wiesz, czy jest w porządku, czy nie, możesz utworzyć metodę narzędziową i użyć jej w następujący sposób:

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

I oczywiście safebyłoby:

public static List safe( List other ) {
    return other == null ? Collections.EMPTY_LIST : other;
}
OscarRyz
źródło
57
Zauważ, że Collections.emptyList () pozwoli uniknąć przydzielania dodatkowego obiektu (IIRC).
Jon Skeet
7
@Jon: Zawsze pytałem siebie, jaki był pożytek z tego emptyList java.sun.com/j2se/1.5.0/docs/api/java/util/ ... Co to jest IIRC?
OscarRyz,
11
IIRC = "Jeśli dobrze pamiętam". I tak, istnieje pojedyncza instancja, która jest zwracana dla wszystkich wywołań funkcji Collections.emptyList ().
ColinD,
To ... właściwie nie odpowiada na pytanie. Dlaczego jest akceptowana odpowiedź?
Christopher Wirt
1
@ChristopherWirt, ponieważ odpowiada na pytanie: D
Tarik
100

Możesz potencjalnie napisać metodę pomocniczą, która zwróci pustą sekwencję, jeśli przekażesz wartość null:

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

Następnie użyj:

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

Chociaż nie sądzę, żebym to zrobił - zwykle używałbym twojej drugiej formy. W szczególności ważne jest „or throw ex” - jeśli naprawdę nie powinno być null, zdecydowanie powinieneś zgłosić wyjątek. Wiesz, że coś poszło nie tak, ale nie znasz rozmiaru szkód. Przerwij wcześniej.

Jon Skeet
źródło
3
Zmieniłbym parametr listy Iterable <T> na iterowalny Iterable <T>, ponieważ nie każda iteracja jest listą.
Lombo,
Uważaj, używając tej metody: ze względu na użycie klasy Collections, użycie tej metody powoduje, że twoja lista jest niezmienna
Tanorix
@tanorix: W jaki sposób?
Jon Skeet
@JonSkeet możesz zobaczyć, że emptyList () klasy Collections zwraca niezmienną listę: docs.oracle.com/javase/8/docs/api/java/util/, więc jeśli użytkownik nie chce, aby jego lista była niezmienna, może być problematyczne
Tanorix
@tanorix: Ale celem tego pytania jest iteracja po zwróconej wartości. To go nie zmienia. Dlatego typ zwracania emptyIfNullto Iterable<T>- jest removewłączona niefortunna metoda Iterator<T>, ale to jedyny jej zmienny aspekt (a jeśli masz pustą kolekcję, dlaczego próbujesz cokolwiek z niej usunąć?) Nie jest jasne, co robisz. sprzeciwiam się tutaj.
Jon Skeet
29

Jest już 2017 rok i możesz teraz korzystać z Apache Commons Collections4

Użycie:

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

Możesz wykonać to samo sprawdzanie bezpieczeństwa null dla innych klas kolekcji za pomocą CollectionUtils.emptyIfNull.

Fred Pym
źródło
2
Będzie działać choć tworzy niepotrzebny obiekt listy. CollectionUtils.ifNotEmpty może być bardziej szczegółowe, ale wydajniejsze i szybsze. Nie żeby miało to duże znaczenie ...
Lawrence,
2
W 2017 spodziewałbym się List.emptyIfNull (list1)
Dima
3
@Lawrence, metoda nie tworzy nowych obiektów listy, używa Collections.emptyList()wewnętrznie, co z kolei zawsze zwraca tę samą wstępnie przydzieloną pustą listę niemodyfikowalną.
Yoory N.
Co się stanie, jeśli wywołasz myobject.getCompanies (). GetAddresses () i oba zwrócą Listę i obie mogą mieć wartość null?
proszek 366
9

W Javie 8 Optional:

for (Object object : Optional.ofNullable(someList).orElse(Collections.emptyList())) {
    // do whatever
}
holmis83
źródło
1
Jest bardziej rozwlekły niż prosty operator trójskładnikowy, taki jak, someList != null ? someList : Collections.emptyList()a także tworzy i natychmiast odrzuca instancję Optionalobiektu.
Yoory N.
2
w jaki sposób te potworne linie są bardziej eleganckie niż prosta instrukcja if (someList == null). Napiszmy wniosek bankowy w jednej linii ...
Andreas Panagiotidis
8

Użyj ArrayUtils.nullToEmptyz commons-langbiblioteki dla tablic

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

Ta funkcjonalność istnieje w commons-langbibliotece, która jest zawarta w większości projektów 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;
}

To jest to samo, co odpowiedź udzielona przez @OscarRyz, ale ze względu na mantrę DRY uważam, że warto o tym wspomnieć. Zobacz stronę projektu Common-Lang . Oto dokumentacja i źródłonullToEmpty API

Maven należy dołączyć do commons-langprojektu, jeśli jeszcze nie jest.

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

Niestety, commons-langnie zapewnia tej funkcji dla Listtypów. W takim przypadku musisz użyć metody pomocniczej, jak wspomniano wcześniej.

public static <E> List<E> nullToEmpty(List<E> list)
{
    if(list == null || list.isEmpty())
    {
        return Collections.emptyList();
    }
    return list;
}
sdc
źródło
7

Jeśli otrzymujesz to Listz wywołania metody, którą implementujesz, nie zwracaj null, zwróć pusty List.

Jeśli nie możesz zmienić implementacji, utkniesz z nullczekiem. Jeśli tak nie jest null, zgłoś wyjątek.

Nie wybrałbym metody pomocniczej, która zwraca pustą listę, ponieważ czasami może się przydać, ale wtedy przyzwyczaiłbyś się do wywoływania jej w każdej pętli, którą wykonujesz, prawdopodobnie ukrywając niektóre błędy.

Lombo
źródło
4

Zmodyfikowałem powyższą odpowiedź, więc nie musisz rzucać z Object

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

a następnie po prostu zadzwoń do listy według

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

Wyjaśnienie: MyOwnObject: Jeśli List<Integer>to MyOwnObject będzie w tym przypadku Integer.

Haris Iltifat
źródło
1

Innym sposobem skutecznego zabezpieczenia się przed wartością zerową w pętli for jest umieszczenie kolekcji w Google Guava, Optional<T>ponieważ można mieć nadzieję, że dzięki temu możliwość efektywnego opróżnienia kolekcji jest jasna, ponieważ klient powinien sprawdzić, czy kolekcja jest obecna Optional.isPresent().

Nico de Wet
źródło
1

Dla każdego, kto nie jest zainteresowany pisaniem własnej statycznej metody bezpieczeństwa zerowego, możesz użyć: commons-lang's org.apache.commons.lang.ObjectUtils.defaultIfNull(Object, Object). Na przykład:

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

ObjectUtils.defaultIfNull JavaDoc

Jacob Briscoe
źródło
Dla mnie ta odpowiedź jest najbardziej elegancka
Truong Nguyen
0

Use, CollectionUtils.isEmpty(Collection coll)metoda, która jest null-bezpiecznym sprawdzaniem, czy określona kolekcja jest pusta.

za to import org.apache.commons.collections.CollectionUtils.

Zależność Mavena

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.0</version>
</dependency>
Swadeshi
źródło
-4
for (Object object : someList) {

   // do whatever
}  throws the null pointer exception.
user6315386
źródło