1概要

このクイックチュートリアルでは、

Java 8で

予測

を連鎖させるさまざまな方法について説明します。


2基本例

まず、単純な

Predicate

** を使用して名前の

List

をフィルタ処理する方法を見てみましょう。

@Test
public void whenFilterList__thenSuccess(){
   List<String> names = Arrays.asList("Adam", "Alexander", "John", "Tom");
   List<String> result = names.stream()
     .filter(name -> name.startsWith("A"))
     .collect(Collectors.toList());

   assertEquals(2, result.size());
   assertThat(result, contains("Adam","Alexander"));
}

この例では、

Predicate

を使用して、名前のリスト(

List

)をフィルタリングして、 “A”で始まる名前だけを残します。

name -> name.startsWith("A")

しかし、複数の

Predicates

を適用したいとしたらどうでしょうか。


3複数のフィルタ

複数の

Predicates

を適用したい場合、

1つの選択肢は単純に複数のフィルタを連鎖させることです:

@Test
public void whenFilterListWithMultipleFilters__thenSuccess(){
    List<String> result = names.stream()
      .filter(name -> name.startsWith("A"))
      .filter(name -> name.length() < 5)
      .collect(Collectors.toList());

    assertEquals(1, result.size());
    assertThat(result, contains("Adam"));
}

「A」で始まり、5未満の長さを持つ名前を抽出することによってリストをフィルタリングするように、例を更新しました。



Predicate

に1つずつ、2つのフィルターを使用しました。


4複雑な

プレディケート


現在は、複数のフィルタを使用する代わりに、複雑な

Predicate

を使用して1つのフィルタを使用できます。

@Test
public void whenFilterListWithComplexPredicate__thenSuccess(){
    List<String> result = names.stream()
      .filter(name -> name.startsWith("A") && name.length() < 5)
      .collect(Collectors.toList());

    assertEquals(1, result.size());
    assertThat(result, contains("Adam"));
}

  • このオプションは最初のオプションよりも柔軟性があります。


    Predicate


    を必要なだけ複雑に構築するためにビット単位の操作を使用できるからです。


5

予測


を組み合わせる

次に、ビット単位演算を使って複雑な

Predicate

を構築したくない場合は、Java 8

Predicate

には

Predicates

を組み合わせるために使用できる便利なメソッドがあります。

  • メソッド

    Predicate.and()



    Predicate.or()

    、および

    Predicate.negate()を使用して

    Predicates__を結合します。


5.1.

Predicate.and()


この例では、

Predicates

を明示的に定義し、次に__Predicate.and()を使用してそれらを組み合わせます。

@Test
public void whenFilterListWithCombinedPredicatesUsingAnd__thenSuccess(){
    Predicate<String> predicate1 =  str -> str.startsWith("A");
    Predicate<String> predicate2 =  str -> str.length() < 5;

    List<String> result = names.stream()
      .filter(predicate1.and(predicate2))
      .collect(Collectors.toList());

    assertEquals(1, result.size());
    assertThat(result, contains("Adam"));
}

ご覧のとおり、構文はかなり直感的であり、メソッド名は操作の種類を示しています。

and()

を使用して、両方の条件を満たす名前のみを抽出することによって

List

をフィルタリングしました。


5.2.

Predicate.or()



Predicateを組み合わせるために

Predicate.or()を使うこともできます。

名前が「J」で始まり、長さが4未満の名前を抽出します。

@Test
public void whenFilterListWithCombinedPredicatesUsingOr__thenSuccess(){
    Predicate<String> predicate1 =  str -> str.startsWith("J");
    Predicate<String> predicate2 =  str -> str.length() < 4;

    List<String> result = names.stream()
      .filter(predicate1.or(predicate2))
      .collect(Collectors.toList());

    assertEquals(2, result.size());
    assertThat(result, contains("John","Tom"));
}


5.3.

Predicate.negate()



Predicates

を組み合わせるときにも

Predicate.negate()

を使用できます。

@Test
public void whenFilterListWithCombinedPredicatesUsingOrAndNegate__thenSuccess(){
    Predicate<String> predicate1 =  str -> str.startsWith("J");
    Predicate<String> predicate2 =  str -> str.length() < 4;

    List<String> result = names.stream()
      .filter(predicate1.or(predicate2.negate()))
      .collect(Collectors.toList());

    assertEquals(3, result.size());
    assertThat(result, contains("Adam","Alexander","John"));
}

ここでは、

or()



negate()

の組み合わせを使用して、「J」で始まる名前または4未満の長さの名前で

List

をフィルタ処理しています。


5.4. インライン

予測

インライン


and()、


or()

、および

negate()を使用するために

Predicatesを明示的に定義する必要はありません。


Predicate

をキャストしてインラインで使用することもできます。

@Test
public void whenFilterListWithCombinedPredicatesInline__thenSuccess(){
    List<String> result = names.stream()
      .filter(((Predicate<String>)name -> name.startsWith("A"))
      .and(name -> name.length()<5))
      .collect(Collectors.toList());

    assertEquals(1, result.size());
    assertThat(result, contains("Adam"));
}


6.

Predicates


のコレクションを組み合わせる

最後に、


Predicates

のコレクションを減らすことによってそれらを連鎖させる方法を見てみましょう。

次の例では、

Predicate.and()を使用して組み合わせた

List

of

Predicates__があります。

@Test
public void whenFilterListWithCollectionOfPredicatesUsingAnd__thenSuccess(){
    List<Predicate<String>> allPredicates = new ArrayList<Predicate<String>>();
    allPredicates.add(str -> str.startsWith("A"));
    allPredicates.add(str -> str.contains("d"));
    allPredicates.add(str -> str.length() > 4);

    List<String> result = names.stream()
      .filter(allPredicates.stream().reduce(x->true, Predicate::and))
      .collect(Collectors.toList());

    assertEquals(1, result.size());
    assertThat(result, contains("Alexander"));
}

基本IDを次のように使用します。

x->true

しかし、

Predicate.or()

を使用してそれらを結合したい場合、それは異なります。

@Test
public void whenFilterListWithCollectionOfPredicatesUsingOr__thenSuccess(){
    List<String> result = names.stream()
      .filter(allPredicates.stream().reduce(x->false, Predicate::or))
      .collect(Collectors.toList());

    assertEquals(2, result.size());
    assertThat(result, contains("Adam","Alexander"));
}


7. 結論

この記事では、

filter()を使用し、

複雑な

Predicates

を構築し、

Predicates.

を組み合わせることによって、Java 8で述語を連鎖させるさまざまな方法を調べました。

完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/core-java-8[GitHubで利用可能]です。