1. 序章

Groovy は、Javaのコア機能を強化するかなりの数のメソッドを提供します。

このチュートリアルでは、要素をチェックし、いくつかのタイプのコレクションでそれを見つけるときに、Groovyがこれをどのように行うかを示します。

2. 要素が存在するかどうかをテストします

まず、特定のコレクションに要素が含まれているかどうかをテストすることに焦点を当てます。

2.1. リスト

Java自体は、java.util.Listを使用してリスト内のアイテムをチェックするいくつかの方法を提供します。

  • containsメソッド
  • indexOfメソッド

GroovyはJava互換言語であるため、安全に使用できます。

例を見てみましょう:

@Test
void whenListContainsElement_thenCheckReturnsTrue() {
    def list = ['a', 'b', 'c']

    assertTrue(list.indexOf('a') > -1)
    assertTrue(list.contains('a'))
}

それとは別に、 Groovyはメンバーシップ演算子を紹介します:

element in list

これは、Groovyが提供する多くの構文糖衣演算子の1つです。 その助けを借りて、コードを単純化できます。

@Test
void whenListContainsElement_thenCheckWithMembershipOperatorReturnsTrue() {
    def list = ['a', 'b', 'c']

    assertTrue('a' in list)
}

2.2. 設定

前の例と同様に、 java.util.Set#containsメソッドとin演算子を使用できます。

@Test
void whenSetContainsElement_thenCheckReturnsTrue() {
    def set = ['a', 'b', 'c'] as Set

    assertTrue(set.contains('a'))
    assertTrue('a' in set)
}

2.3. 地図

Map の場合、キーまたは値のいずれかを直接チェックできます。

@Test
void whenMapContainsKeyElement_thenCheckReturnsTrue() {
    def map = [a: 'd', b: 'e', c: 'f']

    assertTrue(map.containsKey('a'))
    assertFalse(map.containsKey('e'))
    assertTrue(map.containsValue('e'))
}

または、メンバーシップ演算子を使用して、一致するキーを見つけます。

@Test
void whenMapContainsKeyElement_thenCheckByMembershipReturnsTrue() {
    def map = [a: 'd', b: 'e', c: 'f']

    assertTrue('a' in map)
    assertFalse('f' in map)
}

マップで使用する場合は、メンバーシップ演算子を慎重に使用する必要があります。 この演算子は、ブール値で使用すると少し混乱します。 キーの存在をテストするのではなく、基盤となるメカニズムがマップから対応する値を取得し、 それをブール値にキャストします:

@Test
void whenMapContainsFalseBooleanValues_thenCheckReturnsFalse() {
    def map = [a: true, b: false, c: null]

    assertTrue(map.containsKey('b'))
    assertTrue('a' in map)
    assertFalse('b' in map)
    assertFalse('c' in map)
}

上記の例でわかるように、同じ理由で[X48X]null値で使用するのも少し危険です。 Groovyは、falsenullの両方をブール値falseにキャストします。

3. すべての一致とすべての一致

ほとんどの場合、より複雑なオブジェクトで構成されるコレクションを扱います。 このセクションでは、特定のコレクションに少なくとも1つの一致する要素が含まれているかどうか、またはすべての要素が特定の述語に一致するかどうかを確認する方法を示します。

例全体で使用する単純なクラスを定義することから始めましょう。

class Person {
    private String firstname
    private String lastname
    private Integer age

    // constructor, getters and setters
}

3.1. リスト/セット

今回は、Personオブジェクトの簡単なリストを使用します。

private final personList = [
  new Person("Regina", "Fitzpatrick", 25),
  new Person("Abagail", "Ballard", 26),
  new Person("Lucian", "Walter", 30),
]

前述したように、 GroovyはJava互換の言語なので、最初にJava8で導入されたStreamAPIを使用して例を作成しましょう。

@Test
void givenListOfPerson_whenUsingStreamMatching_thenShouldEvaluateList() {
    assertTrue(personList.stream().anyMatch {it.age > 20})
    assertFalse(personList.stream().allMatch {it.age < 30})
}

コレクションに対して直接チェックを実行するGroovyメソッドDefaultGroovyMethods#anyおよびDefaultGroovyMethods#everyを使用することもできます。

@Test
void givenListOfPerson_whenUsingCollectionMatching_thenShouldEvaluateList() {
    assertTrue(personList.any {it.age > 20})
    assertFalse(personList.every {it.age < 30})
}

3.2. 地図

Person#firstnameによってマップされたPersonオブジェクトのMapを定義することから始めましょう。

private final personMap = [
  Regina : new Person("Regina", "Fitzpatrick", 25),
  Abagail: new Person("Abagail", "Ballard", 26),
  Lucian : new Person("Lucian", "Walter", 30)
]

キー、値、またはエントリ全体のいずれかで評価できます。 繰り返しになりますが、最初に StreamAPIを使用しましょう。

@Test
void givenMapOfPerson_whenUsingStreamMatching_thenShouldEvaluateMap() {
    assertTrue(personMap.keySet().stream().anyMatch {it == "Regina"})
    assertFalse(personMap.keySet().stream().allMatch {it == "Albert"})
    assertFalse(personMap.values().stream().allMatch {it.age < 30})
    assertTrue(personMap.entrySet().stream().anyMatch
      {it.key == "Abagail" && it.value.lastname == "Ballard"})
}

そして、GroovyコレクションAPI:

@Test
void givenMapOfPerson_whenUsingCollectionMatching_thenShouldEvaluateMap() {
    assertTrue(personMap.keySet().any {it == "Regina"})
    assertFalse(personMap.keySet().every {it == "Albert"})
    assertFalse(personMap.values().every {it.age < 30})
    assertTrue(personMap.any {firstname, person -> firstname == "Abagail" && person.lastname == "Ballard"})
}

ご覧のとおり、Groovyは、マップを操作するときに Stream APIを適切に置き換えるだけでなく、javaを使用する代わりにMapオブジェクトを直接チェックすることもできます。 util.Map#entrySetメソッド。

4. コレクション内の1つ以上の要素を検索する

4.1. リスト/セット

述語を使用して要素を抽出することもできます。 おなじみのStreamAPIアプローチから始めましょう。

@Test
void givenListOfPerson_whenUsingStreamFind_thenShouldReturnMatchingElements() {
    assertTrue(personList.stream().filter {it.age > 20}.findAny().isPresent())
    assertFalse(personList.stream().filter {it.age > 30}.findAny().isPresent())
    assertTrue(personList.stream().filter {it.age > 20}.findAll().size() == 3)
    assertTrue(personList.stream().filter {it.age > 30}.findAll().isEmpty())
}

ご覧のとおり、上記の例では、 Stream APIがそのアプローチを強制するため、java.util.Optionalを使用して単一の要素を検索します。

一方、Groovyは、はるかにコンパクトな構文を提供します。

@Test
void givenListOfPerson_whenUsingCollectionFind_thenShouldReturnMatchingElements() {
    assertNotNull(personList.find {it.age > 20})
    assertNull(personList.find {it.age > 30})
    assertTrue(personList.findAll {it.age > 20}.size() == 3)
    assertTrue(personList.findAll {it.age > 30}.isEmpty())
}

GroovyのAPIを使用することで、ストリームの作成とフィルタリングをスキップできます

4.2. 地図

マップの場合、いくつかのオプションから選択できます。 キー、値、または完全なエントリの中から要素を見つけることができます。最初の2つは基本的にリストまたはセットであるため、このセクションでは表示するだけです。エントリの検索の例。

以前のpersonMapを再利用しましょう。

@Test
void givenMapOfPerson_whenUsingStreamFind_thenShouldReturnElements() {
    assertTrue(
      personMap.entrySet().stream()
        .filter {it.key == "Abagail" && it.value.lastname == "Ballard"}
        .findAny().isPresent())
    assertTrue(
      personMap.entrySet().stream()
        .filter {it.value.age > 20}
        .findAll().size() == 3)
}

また、簡略化されたGroovyソリューション:

@Test
void givenMapOfPerson_whenUsingCollectionFind_thenShouldReturnElements() {
    assertNotNull(personMap.find {it.key == "Abagail" && it.value.lastname == "Ballard"})
    assertTrue(personMap.findAll {it.value.age > 20}.size() == 3)
}

この場合、メリットはさらに重要です。 java.util.Map#entrySet メソッドをスキップし、Mapで提供される関数でクロージャーを使用します。

5. 結論

この記事では、 Groovyを使用して、要素のチェックといくつかのタイプのコレクションでの要素の検索を簡単にする方法を紹介しました。

いつものように、このチュートリアルで使用される完全なコード例は、GitHubから入手できます。