Правильная реализация лямбда-фильтра - PullRequest
0 голосов
/ 12 декабря 2018

У меня есть случай, когда мне нужно

  • map объекта, если функция отображения выдает исключение, я сопоставляю его с null.
  • filter сопоставленный поток для null объекта, если null, а затем выдать Exception, иначе собрать в List.

Как бы я этого достиг?

list.stream().map(ob-> {
    try {
        // cannot throw only catch 
        return function(ob);
    } catch (Exception e) {
        log.error(e);
        return null;
    }            
}).filter(Objects::isNull).findFirst().orElseThrow(Exception::new);

Теперь мой вопрос: какя должен настроить / реорганизовать вышеупомянутую лямбду в throw new Exception() на null или иначе collect(Collectors.toList()).

Ответы [ 5 ]

0 голосов
/ 12 декабря 2018

Я бы сгенерировал исключение и прямо сейчас оставил бы обработку потока, если бы обнаружил, что мне не нужно перебирать следующие элементы.Зачем продолжать выполнять логику, если она беспомощна?

Так что я бы не стал использовать встроенную map() в этом случае и не использовать потоковую.Я думаю, что это сделало бы вещи очень удобочитаемыми, введя простой метод для отображения:

try{
    return map(list);
} 
catch (Exception e) {
    throw new AnyExceptionYouWant(e);
}

// helper method
List<Bar> map (List<Foo> list) throws Exception{
   List<Bar>> bars = new ArrayList<>();       
   for (Foo foo : list){
          bars.add(function(foo));
   }
   return bars;
 }

Если вы хотите использовать читаемые и простые в обслуживании потоки, вы, вероятно, не должны бросать какие-либо исключения в * 1007.*.Например, вы можете вернуть список Optional с, и было бы просто обработать пустой регистр в вашем потоке.

0 голосов
/ 12 декабря 2018

Если вы намереваетесь сообщить об исключении (что является хорошей идеей), вам никогда не следует сопоставлять его с null.Так как определенные функциональные интерфейсы не позволяют генерировать проверенное исключение, вам следует повторно выбросить его, завернутое в непроверенное исключение:

try {
    List<Object> result = list.stream().map(ob-> {
        try {
            // cannot throw checked exception types
            return function(ob);
        } catch(Exception e) {
            throw new CompletionException(e);
        }
    }).collect(Collectors.toList());
} catch(CompletionException ex) {
    throw (Exception)ex.getCause();
}

Ключевым моментом является то, что это вызовет исходное исключение со всей информацией, содержащейся в нем.вместо создания нового экземпляра через new Exception(), который бы вообще не содержал информации о причине.

Обратите внимание, что в некоторых случаях уже есть выделенные типы исключений, например UncheckedIOException для переноса IOException.В других случаях может быть целесообразнее объявить свой собственный непроверенный тип исключения, чтобы быть уверенным, что он не перепутается с другими исключениями, создаваемыми другими компонентами вашего приложения.

0 голосов
/ 12 декабря 2018

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

Map<Boolean, List<String>> resultMap = list.stream().map(ob-> {
    try {
        return function(ob);
    } catch (Exception e) {
        return null;
    }
}).collect(Collectors.partitioningBy(Objects::isNull));

if(!resultMap.get(Boolean.TRUE).isEmpty()) {
    throw new Exception();
}

return resultMap.get(Boolean.FALSE);

Collectors.partitioningBy(Objects::isNull) вернет Map<Boolean, List<T>>, где true будет отображен в список со всеми элементами, которые соответствуют предикату (Objects::isNull), а false - тем, которые не соответствовали.

Если коллекция true не пуста, вы знаете, что выможет поднять исключение.

0 голосов
/ 12 декабря 2018

Что ж, в лямбдах можно работать с предложениями try-catch, но это не рекомендуется, так как лямбды должны быть как можно короче.

Отделите маппер от нового метода и вызовите его вВместо этого лямбда.

private static final <T, R> R tryMapOrElseNull(T t) {
    try {
        return function(t);
    } catch (Exception e) {
        this.log.error(e);
        return null;
    }
}

Затем используйте метод в качестве ссылки на метод в методе Stream::map.Во-первых, соберите недавно сопоставленные элементы, а затем просто проверьте наличие null.

newList = list.stream().map(MyClass::safeMap).collect(Collectors.toList());

if (newList.contains(null)) {
    throw new Exception();
}
.
0 голосов
/ 12 декабря 2018

Я бы сделал это в два шага, сначала собрал бы в список:

List<T> result = list.stream().map(ob -> {
                try {
                    // cannot throw only catch, since lambda expression 
                    return function(ob);
                } catch (Exception e) {
                    log.error(e);
                    return null;
                }
            }).collect(toList()); 

, где T - тип отображаемых элементов.

, затем проверим на ничтожность:

if(result.contains(null)) {/* throw exeception... */}
else { /* do something else */}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...