Перейти к основному содержимому

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

· 4 мин. чтения

Задача: Медиана двух отсортированных массивов

Даны два отсортированных массива размерами n и m. Найдите медиану слияния этих двух массивов.
Временная сложность решения должна быть O(log(m + n)) ...

ANDROMEDA

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 .