Java Stream Filter с Lambda Expression

1. Въведение

В този бърз урок ще изследваме използването на метода Stream.filter () , когато работим с потоци в Java.

Ще разгледаме как да го използваме и как да обработваме специални случаи с отметнати изключения.

2. Използване на Stream.filter ()

Методът filter () е междинна операция на интерфейса Stream , която ни позволява да филтрираме елементи на поток, които съответстват на даден предикат:

Stream filter(Predicate predicate)

За да видим как работи това, нека създадем клас клиент :

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 () е обработката на колекции.

Нека направим списък с клиенти с повече от 100 точки. За целта можем да използваме ламбда израз:

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

Можем да използваме и справка за метод, която е стенография за ламбда израз:

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

В този случай добавихме метода hasOverHundredPoints към нашия клиентски клас:

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

И в двата случая получаваме един и същ резултат:

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

2.2. Филтриране на колекции с множество критерии

Освен това можем да използваме множество условия с filter () . Например можем да филтрираме по точки и име :

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. Обработка на изключения

Досега използвахме филтъра с предикати, които не създават изключение. Всъщност функционалните интерфейси в Java не декларират никакви отметки или непроверени изключения .

След това ще покажем няколко различни начина за обработка на изключения в ламбда изрази.

3.1. Използване на персонализиран обвивка

Първо ще започнем с добавяне на profilePhotoUrl към нашия клиент :

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

За да се справим с него, една от алтернативите, които можем да използваме, е да го обвием с блок за опити:

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.

Нека започнем с добавяне на зависимостта на функцията за хвърляне към нашия pom:

 pl.touk throwing-function 1.3 

За да се справим с изключенията в предикатите, тази библиотека ни предлага клас ThrowingPredicate , който има метода uncontroced () , за да обгърне отметнатите изключения.

Нека го видим в действие:

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

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

В тази статия видяхме пример за това как да използваме метода filter () за обработка на потоци. Също така проучихме някои алтернативи за справяне с изключенията.

Както винаги, пълният код е достъпен в GitHub.