Фильтр Java Stream с лямбда-выражением

Фильтр Java Stream с лямбда-выражением

1. Вступление

В этом кратком руководстве мы рассмотрим использование методаStream.filter() при работе сStreams in Java.

Мы покажем, как его использовать и как обрабатывать особые случаи с отмеченными исключениями.

2. ИспользуяStream.filter()

Методfilter() - это промежуточная операция интерфейсаStream, которая позволяет нам фильтровать элементы потока, соответствующие заданномуPredicate:

Stream filter(Predicate predicate)

Чтобы увидеть, как это работает, давайте создадим классCustomer:

public class Customer {
    private String name;
    private int points;
    //Constructor and standard getters
}

Кроме того, давайте создадим коллекцию клиентов:

Customer john = new Customer("John P.", 15);
Customer sarah = new Customer("Sarah M.", 200);
Customer charles = new Customer("Charles B.", 150);
Customer mary = new Customer("Mary T.", 1);

List customers = Arrays.asList(john, sarah, charles, mary);

2.1. Фильтрация коллекций

Типичный вариант использования методаfilter() -processing collections.

Составим список клиентов с более чем 100points.. Для этого мы можем использовать лямбда-выражение:

List customersWithMoreThan100Points = customers
  .stream()
  .filter(c -> c.getPoints() > 100)
  .collect(Collectors.toList());

Мы также можем использоватьmethod reference, сокращенное для лямбда-выражения:

List customersWithMoreThan100Points = customers
  .stream()
  .filter(Customer::hasOverHundredPoints)
  .collect(Collectors.toList());

Но для этого случая мы добавили методhasOverHundredPoints в наш классCustomer:

public boolean hasOverHundredPoints() {
    return this.points > 100;
}

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

assertThat(customersWithMoreThan100Points).hasSize(2);
assertThat(customersWithMoreThan100Points).contains(sarah, charles);

2.2. Фильтрация коллекций с использованием нескольких критериев

Кроме того, мы можем использовать несколько условий сfilter(). Например, отфильтруйте поpoints иname:

List charlesWithMoreThan100Points = customers
  .stream()
  .filter(c -> c.getPoints() > 100 && c.getName().startsWith("Charles"))
  .collect(Collectors.toList());

assertThat(charlesWithMoreThan100Points).hasSize(1);
assertThat(charlesWithMoreThan100Points).contains(charles);

3. Обработка исключений

До сих пор мы использовали фильтр с предикатами, не вызывающими исключения. Действительно,functional interfaces in Java don’t declare any checked or unchecked exception.

Далее мы собираемся показать несколько различных способов обработкиexceptions in lambda expressions.

3.1. Использование настраиваемой оболочки

Сначала мы начнем добавлять к нашемуCustomer aprofilePhotoUrl:

private String profilePhotoUrl;

Кроме того, давайте добавим простой методhasValidProfilePhoto() для проверки доступности профиля:

public boolean hasValidProfilePhoto() throws IOException {
    URL url = new URL(this.profilePhotoUrl);
    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    return connection.getResponseCode() == HttpURLConnection.HTTP_OK;
}

Мы видим, что методhasValidProfilePhoto() выдаетIOException. Теперь, если мы попытаемся отфильтровать клиентов с помощью этого метода:

List customersWithValidProfilePhoto = customers
  .stream()
  .filter(Customer::hasValidProfilePhoto)
  .collect(Collectors.toList());

Мы увидим следующую ошибку:

Incompatible thrown types java.io.IOException in functional expression

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

List customersWithValidProfilePhoto = customers
  .stream()
  .filter(c -> {
      try {
          return c.hasValidProfilePhoto();
      } catch (IOException e) {
          //handle exception
      }
      return false;
  })
  .collect(Collectors.toList());

Если нам нужно выбросить исключение из нашего предиката, мы можем заключить его в непроверенное исключение, напримерRuntimeException.

3.2. ИспользуяThrowingFunction

В качестве альтернативы мы можем использовать библиотекуThrowingFunction.

ThrowingFunction - это библиотека с открытым исходным кодом, которая позволяет нам обрабатывать отмеченные исключения в функциональных интерфейсах Java.

Начнем с добавленияthrowing-function dependency к нашему pom:


    pl.touk
    throwing-function
    1.3

Для обработки исключений в предикатах эта библиотека предлагает нам классThrowingPredicate, в котором есть методunchecked() для обертывания проверенных исключений.

Давайте посмотрим на это в действии:

List customersWithValidProfilePhoto = customers
  .stream()
  .filter(ThrowingPredicate.unchecked(Customer::hasValidProfilePhoto))
  .collect(Collectors.toList());

4. Заключение

В этой статье мы увидели пример того, как использовать методfilter() для обработки потоков. Кроме того, мы исследовали некоторые альтернативы для обработки исключений.

Как всегда доступен полный кодover on GitHub.