Java поток, фильтр, а затем сделать что-то с результирующей коллекцией - PullRequest
0 голосов
/ 03 марта 2020

Цель

final List<T> listOfThings = ...;

listOfThings.stream()
    .filter(...) // returns a Stream<T>
    .then(filteredListOfThings -> {
        // How do I get here so I can work on the newly filtered collection
        // in a fluent way w/out collecting the result to a variable?
        // For example, if I need to process the elements but don't 
        // care about them in their current form outside this chain.
    });

Задача

В Engli sh, учитывая список чего-либо, я хотел бы передать список, отфильтруйте его, а затем оперируйте полным фильтрованным результатом . Я могу выполнить sh с помощью необязательного, но это не чистый IMO:

final List<T> listOfThings = ...;

Optional
    .of(listOfThings.stream()
        .filter(...) // returns a Stream<T>
        .collect(Collectors.toList()))
    .map(filteredListOfThings -> {
        // I'm here, now, but would like to not have to wrap it in an Optional<T>
    });

Было бы здорово, если бы был then или подобный метод на Stream<T>, который возвращает Stream<T> в учесть дальнейшее сцепление, что позволяет мне работать со всем набором результатов в лямбда-выражении без объявления внешней переменной.

Ответы [ 2 ]

5 голосов
/ 03 марта 2020

Не усложняйте, чем нужно.

Назначьте результат collect переменной, затем оперируйте этой переменной:

List<T> filteredListOfThings = ... .collect(toList());

// Now use filteredListOfThings.

* Значение 1007 * всегда будет иметь значение, даже если это пустой список, поэтому нет смысла использовать Optional.

. И не так уж много различий между c между filteredListOfThings как параметром лямбда и явная переменная; но у вас больше гибкости в том, что вы можете делать во время обработки (возврат из методов, создание проверенных исключений и т. д. c).

1 голос
/ 03 марта 2020

Я бы хотел обработать список, отфильтровать его, а затем обработать весь отфильтрованный результат.

Обратите внимание, что поток также может быть бесконечным;)

Таким образом, получение бесконечного списка результатов не очень хорошая идея.

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

Например, следующий код ничего не печатает:

Stream<String> stream = Stream.of("hello","how","are", "you").filter(this::startsWithH)

private boolean startsWithH(String elem) {
  System.out.println("Filtering element " + elem); 
  return elem.startsWith("h");
}

Теперь, когда вы применяете терминальную операцию, она все равно будет работать поэлементно:

Пример выполнения:

Stream<String> stream = Stream.of("hello","how","are", "you")
.filter(this::startsWithH)
.map(String::toUpperCase)

stream.collect(toList());

В этом примере выдается следующая цепочка выполнения:

  1. filter ("hello")
  2. map ("hello")
  3. filter ("how" )
  4. map ("как")
  5. filter ("are") <--- отфильтровано, вызов карты не будет выполнен </li>
  6. filter ("you" ) <--- отфильтровано, вызов map не будет выполняться </li>

Но если это так, вы не сможете по-настоящему работать с "целым" потоком в примере в этом вопросе (хорошо, есть операции с состоянием, которые должны работать со всем потоком, например sort , но это совсем другая история).

Другими словами, если вы хотите получить данные как сбор, вы должны, ну, собирать данные. Это больше не будет потоком.

Для этого вы должны использовать .collect(). И если у вас есть бесконечный поток, не забудьте позвонить limit beforehands;)

...