ラムダ式のJavaストリームフィルタ

Lambda Expressionを使用したJava Stream Filter

1. 前書き

このクイックチュートリアルでは、Streams in Javaを操作するときのStream.filter()メソッドの使用について説明します。

これを使用する方法と、チェックされた例外を含む特殊なケースを処理する方法を示します。

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()で複数の条件を使用できます。 たとえば、pointsnameでフィルタリングします。

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. カスタムラッパーの使用

まず、CustomerprofilePhotoUrl:を追加します。

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で利用できます。