Проверка нуля в расширенном цикле for


172

Каков наилучший способ защиты от нуля в цикле 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это не то же самое, что пустая коллекция.
Том Хотин - tackline

6
@GregMattes Как февральский вопрос является дубликатом октябрьского вопроса?
Val

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

Ответы:


228

Вам лучше проверить, откуда вы получили этот список.

Пустой список - это все, что вам нужно, потому что пустой список не подведет.

Если вы получили этот список откуда-то еще и не знаете, нормально ли это, вы можете создать служебный метод и использовать его следующим образом:

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
Тарик

100

Вы могли бы потенциально написать вспомогательный метод, который возвращал бы пустую последовательность, если вы передали значение null:

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

Тогда используйте:

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

Я не думаю, что на самом деле сделал бы это - я бы обычно использовал вашу вторую форму. В частности, важно «или throw ex» - если оно действительно не должно быть нулевым, вы должны обязательно выбросить исключение. Вы знаете, что что- то пошло не так, но вы не знаете масштаб ущерба. Прервать рано.


3
Я бы изменил параметр списка Iterable <T> на Iterable <T> iterable, так как не каждый повторяемый список.
Ломбо

Будьте осторожны, используя этот метод: из-за использования класса Collections, использование этого метода подразумевает, что ваш список будет неизменным
Tanorix,

@tanorix: Каким образом?
Джон Скит

@JonSkeet вы можете видеть, что emptyList () класса Collections возвращает неизменный список: docs.oracle.com/javase/8/docs/api/java/util/… так что если пользователь не хочет, чтобы его список был неизменным, он может быть проблематичным
Tanorix

@tanorix: Но смысл этого вопроса в том, чтобы повторить возвращаемое значение. Это не меняет его. Вот почему возвращаемый тип emptyIfNullявляется Iterable<T>- есть несчастный removeметод на Iterator<T>, но это единственный изменяемый аспект его (? И если у вас есть пустая коллекция, почему вы пытаетесь удалить что - нибудь из него) Это не ясно , что вы» Возражаю здесь.
Джон Скит

29

Уже 2017 год, и теперь вы можете использовать Apache Commons Collections4

Использование:

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

Вы можете сделать ту же проверку на нулевую безопасность для других классов Collection с помощью CollectionUtils.emptyIfNull.


2
Будет работать, хотя создает ненужный список объектов. CollectionUtils.ifNotEmpty может быть более многословным, но более эффективным и быстрым. Не то чтобы это имело большое значение ...
Лоуренс

2
В 2017 году я ожидаю List.emptyIfNull (list1)
Дима

3
@Lawrence, метод не создает новые объекты списка, он использует его Collections.emptyList()внутренне, что в свою очередь всегда возвращает один и тот же предварительно выделенный пустой неизменяемый список.
Йори Н.

Что если вы вызываете myobject.getCompanies (). GetAddresses (), и оба возвращают List, и оба могут иметь значение null?
powder366

9

С Java 8 Optional:

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

1
Он более многословен, чем простой троичный оператор, как, someList != null ? someList : Collections.emptyList()а также создает и немедленно выбрасывает экземпляр Optionalобъекта.
Йори Н.

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, но ради СУХОЙ мантры, я думаю, это стоит отметить. См. Страницу проекта « Общие достояния ». Вот документация по nullToEmptyAPI и источник

Maven запись для включения 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

Я изменил приведенный выше ответ, поэтому вам не нужно приводить из объекта

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 будет Integer в этом случае.


1

Еще один способ эффективно защититься от нуля в цикле 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)метод, который является Null-safe, проверяет, является ли указанная коллекция пустой.

для этого import org.apache.commons.collections.CollectionUtils.

Maven зависимость

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