Groovyのコレクションで要素を見つける
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は、falseとnullの両方をブール値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でから入手できます。