Lambda Expressionを使用したJava Stream Filter
1. 前書き
このクイックチュートリアルでは、Streams in Javaを操作するときのStream.filter()メソッドの使用について説明します。
これを使用する方法と、チェックされた例外を含む特殊なケースを処理する方法を示します。
2. Stream.filter()の使用
filter()メソッドは、Streamインターフェイスの中間操作であり、特定のPredicate:に一致するストリームの要素をフィルタリングできます。
Stream 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 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に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
それを処理するために使用できる代替手段の1つは、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
述語の例外を処理するために、このライブラリは、チェックされた例外をラップするunchecked()メソッドを持つThrowingPredicateクラスを提供します。
実際の動作を見てみましょう。
List customersWithValidProfilePhoto = customers
.stream()
.filter(ThrowingPredicate.unchecked(Customer::hasValidProfilePhoto))
.collect(Collectors.toList());
4. 結論
この記事では、filter()メソッドを使用してストリームを処理する方法の例を見ました。 また、例外を処理するためのいくつかの代替案を検討しました。
いつものように、完全なコードはover on GitHubで利用できます。