Есть ли способ избежать проверки на ноль перед началом итерации цикла for-each?

Каждый раз, когда мне приходится перебирать коллекцию, я заканчиваю проверку на нулевое значение, как раз перед началом итерации цикла for-each. Как это:

if( list1 != null ){
    for(Object obj : list1){

    }
}

Есть ли более короткий путь, чтобы мы могли избежать записи блока if? Примечание: я использую Java 5, и застряну с ним некоторое время.

9 ответов

Решение

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

Если возможно, вы должны разработать свой код так, чтобы коллекции не null на первом месте.

null коллекции - плохая практика (по этой причине); Вы должны использовать пустые коллекции вместо этого. (например, Collections.emptyList())

В качестве альтернативы, вы можете сделать класс-оболочку, который реализует Iterable и берет коллекции, и обрабатывает null коллекция.
Вы могли бы тогда написать foreach(T obj : new Nullable<T>(list1))

public <T extends Iterable> T nullGuard(T item) {
  if (item == null) {
    return Collections.EmptyList;
  } else {
    return item;
  }
}

позволит вам написать

for (Object obj : nullGuard(list)) {
  ...
}

Конечно, это действительно просто перемещает сложность в другом месте.

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

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

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

В Java 8 есть другое решение, доступное с помощью java.util.Optional и ifPresent-метод.

Optional.ofNullable(list1).ifPresent(l -> l.forEach(item -> {/* do stuff */}));

Таким образом, не решение для точной проблемы, но это единственное и, возможно, более элегантный.

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

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

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

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

Apache Commons

for (String code: ListUtils.emptyIfNull(codes)) {

}           

Google Guava

for (String code: Optional.of(codes).get()) {

}

Насколько короче вы хотите, чтобы это было? Это всего лишь лишние 2 строки И это понятная и лаконичная логика.

Я думаю, что более важная вещь, которую вы должны решить, это если null является действительным значением или нет. Если они недействительны, вы должны написать свой код, чтобы предотвратить это. Тогда вам не понадобится такая проверка. Если вы идете получить исключение во время выполнения foreach цикл, это признак того, что где-то в вашем коде есть ошибка.

1) если list1 является членом класса, создайте список в конструкторе, чтобы он был и не был нулевым, хотя и пустым.

2) for (Объект obj: list1!= Null? List1: new ArrayList())

Другой способ Java 8+ - создать метод forEach, который не дает сбоев при использовании null значение:

public static <T> void forEach(Iterable<T> set, Consumer<T> action) {
    if (set != null) {
        set.forEach(action);
    }
}

Использование собственного определения foreach близок к родному Java 8:

ArrayList<T> list = null;

//java 8+ (will throw a NullPointerException)
list.forEach(item -> doSomething(...) );

//own implementation
forEach(list, item -> doSomething(...) );
Другие вопросы по тегам