倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

あんたに GDK の何が分かるっていうの!? (Object 編4) コンテナ・メソッド 後編

前回に引き続き、今回も GDK が Object クラスに追加しているコンテナ・メソッドを見てきます。 今回見ていくのは find で始まる名前のメソッド。 結構あれこれあるんですね。 今回見ていくメソッドは以下のもの:

Collection findAll(Closure closure)
Collection findAll()

Object find(Closure closure)
Object find()

Object findResult(Closure closure)
Object findResult(Object defaultResult, Closure closure)

int findIndexOf(Closure closure)
int findIndexOf(int startIndex, Closure closure)

int findLastIndexOf(Closure closure)
int findLastIndexOf(int startIndex, Closure closure)

List findIndexValues(Closure closure)    // 返り値は List<Integer>
List findIndexValues(Number startIndex, Closure closure)

引数をとらない findAll(), find() メソッドは、前回と同じく恒等変換(引数をそのまま返す)クロージャ Closure.IDENTITY を引数として渡したのと同じです。

メソッド 返り値 since 説明
findAll(Closure)
findAll()
Collection 1.6.0
1.8.1
引数のクロージャを適用して true を返した要素を集めて Collection として返す
find(Closure)
find()
Object 1.0
1.8.1
引数のクロージャを適用して true を返した最初の要素を返す
findResult(Closure)
findResult(Object, Closure)
Object 1.7.5 要素に引数のクロージャを適用して null でなかった最初の結果を返す
findIndexOf(Closure)
findIndexOf(int, Closure)
int 1.5.0 引数のクロージャを適用して true を返す最初の要素の番号を返す
findLastIndexOf(Closure)
findLastIndexOf(int, Closure)
int 1.5.2 引数のクロージャを適用して true を返す最後の要素の番号を返す
findIndexValues(Closure)
findIndexValues(Number, Closure)
List 1.5.2 引数のクロージャを適用して true を返す要素の番号をリストにして返す
  • findAll() メソッドは関数型言語filter と同じですね。
  • findResult() は変換後の結果を返すところが find() と異なります。
  • findIndexOf(), findLastIndexOf(), findIndexValues() のインデックス検索メソッドに int 値を渡すと、その番号以降(指定した番号を含む)にインデックス検索が実行されます。

では各メソッドのサンプルを見ていきましょう。

findAll() メソッド

findAll() は関数型言語の filter に相当するメソッドで、引数のクロージャが true を返すかどうかでフィルタリングするメソッドです。 前回見た grep() と同じようなものですね。

def lang = ['Java', 'Groovy', 'Scala', 'Clojure', 'Kotlin', 'Jython', 'JRuby']
assert lang.findAll{ it.startsWith 'J' } == ['Java', 'Jython', 'JRuby']

assert (0..10).findAll() == 1..10    // 0(false と評価される)以外を通すフィルタ

2つ目の引数をとらない findAll() では Closure.IDENTITY が指定されているのと同じです。 findAll() は結構多用するメソッドかと。

find() メソッド

find() は findAll() 似ていますが、引数のクロージャを適用して true を返す要素を1つ返します。 ドキュメントで「最初の」と指定されているので、リストや配列では番号順で最初のものが返される仕様でしよう。 Groovy では Set もデフォルトで LinkedHashSet (順序を保持する Set)なので、この場合も同様。 普通の HashSet とかだとどれが返されるかは JVM のみぞ知る(知らない?):

def lang = ['Java', 'Groovy', 'Scala', 'Clojure', 'Kotlin', 'Jython', 'JRuby']

assert lang.find{ it.contains 'o' } == 'Groovy'
assert (0..10).find() == 1

findResult() メソッド

findResult() は引数のクロージャを各要素に適用して、返された値が null でない最初のオブジェクトを返します。 クロージャによる変換後のオブジェクトがカエサル点が find() と異なります:

def lang = ['Java', 'Groovy', 'Scala', 'Clojure', 'Kotlin', 'Jython', 'JRuby']

assert lang.findResult{ it.size() >= 7 ? it.toUpperCase() : null } == 'CLOJURE'
assert lang.findResult{ it.toLowerCase() } == 'java'
assert lang.findResult('javascript'){ it.endsWith('t') ? it.toLowerCase() : null } == 'javascript'

1つ目、3つ目のものは3項演算 ?: を使って無理矢理 null を返してるのがぎこちない(findResult() の前に findAll() とかを適用しておく方が自然)ですが、まぁ、あくまでサンプルですから。 3つ目のものは、全ての要素が null を返した場合のデフォルト値を指定('javascript')しています。

findIndexOf(), findLastIndexOf(), findIndexValue() メソッド

これらのメソッドは、条件に合う要素の番号を返すインデックス検索メソッド。 索引メソッドと言った方がいいか。 Java の String クラスに定義されている indexOf(), lastIndexOf() とかと同じっス。 String クラスのものは文字か文字列をしていますが、ここで扱うメソッドではクロージャを指定して true を返すかどうかで合ってるかどうかを指定しています。 サンプルはこんな感じ:

def lang = ['Java', 'Groovy', 'Scala', 'Clojure', 'Kotlin', 'Jython', 'JRuby']

// findIndexOf()
assert lang.findIndexOf{ it.contains 'o' } == 1
assert lang.findIndexOf(3){ it.contains 'o' } == 3

// findLastIndexOf()
assert lang.findLastIndexOf{ it.contains 'o'} == 5
assert lang.findLastIndexOf(3){ it.contains 'o' } == 5    // lastIndexOf() でも指定した int 値は検索開始位置
assert lang.findLastIndexOf(6){ it.contains 'o' } == -1

// findIndexValues()
assert lang.findIndexValues{ it.contains 'o' } == [1, 3, 4, 5]
assert lang.findIndexValues(3){ it.contains 'o' } == [3, 4, 5]

まぁ、特に問題はないかと。

次回デバッグ用のメソッド(予定)。

プログラミングGROOVY

プログラミングGROOVY