1. Введение
В этом кратком руководстве мы рассмотрим использование метода Stream.filter()
при работе с потоками
в Java .
Мы рассмотрим, как его использовать и как обрабатывать особые случаи с проверенными исключениями.
2. Использование Stream.filter()
Метод filter()
— это промежуточная операция интерфейса Stream
, которая позволяет нам фильтровать элементы потока, соответствующие заданному Predicate:
Stream<T> filter(Predicate<? super T> 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<Customer> customers = Arrays.asList(john, sarah, charles, mary);
2.1. Фильтрация коллекций
Обычный вариант использования метода filter()
— обработка коллекций .
Давайте составим список клиентов с более чем 100 баллами.
Для этого мы можем использовать лямбда-выражение:
List<Customer> customersWithMoreThan100Points = customers
.stream()
.filter(c -> c.getPoints() > 100)
.collect(Collectors.toList());
Мы также можем использовать ссылку на метод , которая является сокращением для лямбда-выражения:
List<Customer> 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()
. Например, мы можем фильтровать по точкам
и имени
:
List<Customer> charlesWithMoreThan100Points = customers
.stream()
.filter(c -> c.getPoints() > 100 && c.getName().startsWith("Charles"))
.collect(Collectors.toList());
assertThat(charlesWithMoreThan100Points).hasSize(1);
assertThat(charlesWithMoreThan100Points).contains(charles);
3. Обработка исключений
До сих пор мы использовали фильтр с предикатами, которые не генерируют исключение. Действительно, функциональные интерфейсы в Java не объявляют ни проверенных, ни непроверенных исключений .
Далее мы покажем несколько различных способов обработки исключений в лямбда-выражениях .
3.1. Использование пользовательской оболочки
Во- первых, мы начнем с добавления profilePhotoUrl
к нашему Customer
:
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<Customer> customersWithValidProfilePhoto = customers
.stream()
.filter(Customer::hasValidProfilePhoto)
.collect(Collectors.toList());
Мы увидим следующую ошибку:
Incompatible thrown types java.io.IOException in functional expression
Чтобы справиться с этим, одна из альтернатив, которые мы можем использовать, — это обернуть его блоком try-catch:
List<Customer> 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-функции
в наш pom :
<dependency>
<groupId>pl.touk</groupId>
<artifactId>throwing-function</artifactId>
<version>1.3</version>
</dependency>
Для обработки исключений в предикатах эта библиотека предлагает нам класс ThrowingPredicate , который имеет метод
unchecked()
для переноса проверенных исключений.
Давайте посмотрим на это в действии:
List customersWithValidProfilePhoto = customers
.stream()
.filter(ThrowingPredicate.unchecked(Customer::hasValidProfilePhoto))
.collect(Collectors.toList());
4. Вывод
В этой статье мы увидели пример использования метода filter()
для обработки потоков. Мы также изучили некоторые альтернативы для обработки исключений.
Как всегда, полный код доступен на GitHub .