Нульова перевірка в поліпшеному циклі


172

Який найкращий спосіб захистити від null в циклі for для Java?

Це здається некрасивим:

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

Або

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

Не може бути іншого способу. Чи повинні вони помістити його в саму forконструкцію, якщо вона є нульовою, тоді не запускайте цикл?


2
Вам, мабуть, краще кинути NPE. nullне те саме, що порожня колекція.
Том Хотін - тайклін

6
@GregMattes Як лютий питання є дублікатом жовтневого питання?
Валь

1
Просто потрібно використовувати Collections.nonNullElementsIn (...): stackoverflow.com/a/34913556/5637185
Джеффрі Діллі

Відповіді:


227

Вам слід краще перевірити, звідки ви отримуєте цей список.

Порожній список - все, що вам потрібно, тому що порожній список не вийде з ладу.

Якщо ви отримаєте цей список з іншого місця та не знаєте, чи це нормально чи ні, ви можете створити корисний метод і використовувати його так:

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

І звичайно safeбуло б:

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

57
Зауважте, що Collections.emptyList () не дозволить виділити додатковий об'єкт (IIRC).
Джон Скіт

7
@Jon: Я завжди запитував себе, чим користувався той emptyList java.sun.com/j2se/1.5.0/docs/api/java/util/… Що таке IIRC?
OscarRyz

11
IIRC = "Якщо я пам'ятаю правильно". І так, є одиночний екземпляр, який повертається для всіх викликів у Collections.emptyList ().
ColinD

Це ... насправді не відповідає на питання. Чому прийнята відповідь?
Крістофер Вірт

1
@ChristopherWirt тому, що він відповідає на питання: D
Tarik

100

Ви потенційно можете написати хелперний метод, який повернув порожню послідовність, якщо ви перейшли в нуль:

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

Потім використовуйте:

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

Я не думаю, що насправді б це зробив - зазвичай я використовував вашу другу форму. Зокрема, важливо "або кинути екс" - якщо це дійсно не повинно бути нульовим, ви обов'язково повинні кинути виняток. Ви знаєте, що щось пішло не так, але ви не знаєте ступеня шкоди. Покиньте рано.


3
Я змінив би параметр списку Iterable <T> на Iterable <T> iterable, оскільки не кожен ітерабельний список є.
Ломбо

Будьте обережні, використовуючи цей метод: через використання класу Collections, використання цього методу передбачає незмінність вашого списку
Tanorix

@tanorix: Яким способом?
Джон Скіт

@JonSkeet ви можете бачити, що порожній список () з колекцій повертає незмінний список: docs.oracle.com/javase/8/docs/api/java/util/…, тож якщо користувач не хоче, щоб його список був незмінний, він може бути проблематичним
Танорікс

@tanorix: Але суть цього питання полягає в повторенні повернутого значення. Це не змінює його. Ось чому повертається тип emptyIfNullє Iterable<T>- є нещасний removeметод на Iterator<T>, але це єдиний змінний аспект його (? І якщо у вас є порожня колекція, чому ви намагаєтеся видалити що - небудь з нього) Це не ясно , що ви " Ви заперечуєте тут.
Джон Скіт

29

Вже 2017 рік, і тепер ви можете використовувати колекції Apache Commons4

Використання:

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

Ви можете зробити те саме, що перевіряє нуль для інших класів колекції CollectionUtils.emptyIfNull.


2
Працює, хоча створює зайвий об’єкт списку. A CollectionUtils.ifNotEmpty може бути більш багатослівним, але більш ефективним і швидшим. Не те, щоб це мало значить ...
Лоуренс

2
У 2017 році я б очікував List.emptyIfNull (list1)
Діма

3
@Lawrence, метод не створює нових об'єктів списку, він використовує Collections.emptyList()внутрішньо, що, у свою чергу, завжди повертає той самий попередньо розміщений порожній немодифікований список.
Yoory N.

Що робити, якщо ви викликаєте myobject.getCompanies (). GetAddresses () і обидва повертають список, і обидва можуть бути недійсними?
порошок366

9

З Java 8 Optional:

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

1
Його більш багатослівний, ніж простий потрійний оператор, як, someList != null ? someList : Collections.emptyList()а також створює і негайно викидає екземпляр Optionalоб'єкта.
Yoory N.

2
як ці монстрові лінії є більш витонченими, ніж просте твердження if (someList == null). Давайте запишемо банківську заявку в один рядок ...
Андреас Панагіотидіс

8

Використання ArrayUtils.nullToEmptyз commons-langбібліотеки для масивів

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

Ця функціональність існує в commons-langбібліотеці, яка входить до більшості 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;
}

Це те саме, що відповідь, яку дав @OscarRyz, але заради мари DRY , я вважаю, що це варто відзначити. Дивіться сторінку проекту commons-lang . Ось документація та джерелоnullToEmpty API

Додано запис, який потрібно включити commons-langу ваш проект, якщо його ще немає.

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

На жаль, commons-langне надає цю функціональність для Listтипів. У цьому випадку вам доведеться скористатися допоміжним методом, як згадувалося раніше.

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

7

Якщо ви отримуєте це Listз виклику методу, який ви реалізуєте, тоді не повертайтеся null, поверніть порожнє List.

Якщо ви не можете змінити реалізацію, тоді ви застрягли з nullчеком. Якщо цього не повинно бути null, то киньте виняток.

Я б не звертався за допоміжним методом, який повертає порожній список, оскільки він може бути корисним кілька разів, але тоді ви звикли б називати його в кожному циклі, який ви створюєте, можливо, приховуючи деякі помилки.


4

Я змінив вищевказану відповідь, тому вам не потрібно робити передачу з Object

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

а потім просто зателефонувати за списком

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

Пояснення: MyOwnObject: Якщо List<Integer>тоді, MyOwnObject буде цілим у цьому випадку.


1

Інший спосіб ефективного захисту від нуля в циклі for for - обернути свою колекцію за допомогою Google Guava, Optional<T>оскільки це, сподіваємось, робить можливість фактично порожньої колекції зрозумілою, оскільки, як очікується, клієнт перевірить, чи існує колекція Optional.isPresent().


1

Для всіх, хто не зацікавлений у написанні власного статичного методу безпеки нуля, ви можете використовувати: commons-lang's org.apache.commons.lang.ObjectUtils.defaultIfNull(Object, Object). Наприклад:

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

ObjectUtils.defaultIfNull JavaDoc


Для мене ця відповідь є найелегантнішою
Труонг Нгуен

0

Використання, CollectionUtils.isEmpty(Collection coll)метод, який є безпечним для перевірки, чи вказана колекція порожня.

для цього import org.apache.commons.collections.CollectionUtils.

Залежна залежність

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.