今回はGroovy のコレクションで注意するべきことについて。 『Groovyイン・アクション』Chapter4 を参考にしています(一覧)。
- 作者: Dierk Konig,Andrew Glover,Paul King,Guillaume Laforge,Jon Skeet,杉浦孝,櫻井正樹,須江信洋,関谷和愛,佐野徹郎,寺沢尚史
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2008/09/27
- メディア: 単行本(ソフトカバー)
- 購入: 5人 クリック: 146回
- この商品を含むブログ (121件) を見る
コピーと変更のセマンティクス
『Groovyイン・アクション』に書かれているメソッドの命名規約(ただし、公式ではない)。 ただし例外もあるので、使用の際に振る舞いを疑問に思ったときは、ドキュメントを確認するか、簡単なテストコードを書いてみましょう。
規約 | 例 | 反例 |
---|---|---|
レシーバを変更する → コレクションを返さない | add() addAll() remove() removeAll() retainAll() |
sort() |
コレクションを返す → レシーバを変更しない | grep() findAll() collect() |
sort() |
命令的な名前を持つ → レシーバを変更する | add() addAll() remove() removeAll() retainAll() sort() |
collect() grep() findAll() |
演算子に対しても対応するメソッド名にこの規約を適用できる | << → leftShift() + → plus() |
文字列の << |
以下、Java SE 6, Groovy 1.7.1 で List のメソッドについて具体的に見ていきます。
レシーバを変更する List のメソッド
レシーバを変更するメソッドは、概ねコレクションを返しません。 Java SE 6, Groovy 1.7.1 では、例外は
- sort()
- unique()
- leftShift() (<<)
だけです(たぶん)。
メソッド名 | 返り値 | コレクションを返す | 定義されている型 |
---|---|---|---|
add(E e) | boolean | List (JDK) | |
add(int index, E element) | void | List (JDK) | |
addAll(Collection<? extends E> c) addAll(int index, Collection<? extends E> c) |
boolean | List (JDK) | |
set(int index, E element) | E | List (JDK) | |
remove(int index) | E | List (JDK) | |
remove(Object o) | boolean | List (JDK) | |
removeAll(Collection c) | boolean | List (JDK) | |
retainAll(Collection c) | boolean | List (JDK) | |
clear() | void | List (JDK) | |
putAt(int, Object) putAt(EmptyRange, Object) putAt(EmptyRange, Collection) putAt(IntRange, Collection) putAt(IntRange, Object) putAt(List, List) putAt(List, Object) |
void | List (Groovy JDK) | |
pop() | Object | List (Groovy JDK) | |
push(Object) | boolean | List (Groovy JDK) | |
sort() sort(Comparator) sort(Closure) |
List | ○ | Collection (Groovy JDK) |
unique() unique(Closure) unique(Comparator) |
Collection | ○ | Collection (Groovy JDK) |
leftShift(Object) | Collection | ○ | Collection (Groovy JDK) |
コレクションを返す List のメソッド
コレクションを返すメソッドは、概ねレシーバを変更しません。 Java SE 6, Groovy 1.7.1 では、例外は上記の「レシーバを変更する List のメソッド」の例外と同じ。
メソッド名 | 返り値 | レシーバを変更する | 定義されている型 |
---|---|---|---|
iterator() | Iterator |
List (JDK) | |
<E> listIterator() <E> listIterator(int index) |
ListIterator<E> | List (JDK) | |
subList(int fromIndex, int toIndex) | List<E> | List (JDK) | |
toArray() | Object[] | List (JDK) | |
<T> toArray(T[] a) | T[] | List (JDK) | |
asImmutable() | List | List (Groovy JDK) | |
asSynchronized() | List | List (Groovy JDK) | |
getAt(Range) getAt(EmptyRange) getAt(Collection) |
List | List (Groovy JDK) | |
minus(Collection) minus(Object) |
List | List (Groovy JDK) | |
tail() | List | List (Groovy JDK) | |
reverse() | List | List (Groovy JDK) | |
reverseEach(Closure) | List | List (Groovy JDK) | |
permutations() | Set | List (Groovy JDK) | |
subsequences() | Set | List (Groovy JDK) | |
transpose() | List | List (Groovy JDK) | |
asList() | List | Collection (Groovy JDK) | |
toList() | List | Collection (Groovy JDK) | |
intersect(Collection) | Collection | Collection (Groovy JDK) | |
getAt(String) | List | Collection (Groovy JDK) | |
findAll(Closure) | Collection | Collection (Groovy JDK) | |
collect(Closure) collect(Collection, Closure) |
Collection | Collection (Groovy JDK) | |
collectAll(Closure) collectAll(Collection, Closure) |
Collection | Collection (Groovy JDK) | |
sort() sort(Comparator) sort(Closure) |
List | ○ | Collection (Groovy JDK) |
unique() unique(Closure) unique(Comparator) |
Collection | ○ | Collection (Groovy JDK) |
multiply(Number) | List | Collection (Groovy JDK) | |
plus(Collection) plus(Object) |
Collection | Collection (Groovy JDK) | |
leftShift(Object) | Collection | ○ | Collection (Groovy JDK) |
flatten() flatten(Closure) |
Collection | Collection (Groovy JDK) | |
split(Closure) | Collection | Collection (Groovy JDK) | |
eachPermutation(Closure) | Iterator | Collection (Groovy JDK) | |
combinations() | List | Collection (Groovy JDK) |
List#asImmutable() メソッド
List のメソッドの振る舞いを見ている際に asImmutable() メソッドの振る舞いが気になったのでメモ。
asImmutable() メソッドによって返された List は当然変更不可ですが、元の List の要素を変更すると、その変更が immutable とした List にも反映されます。
list = [1, 2, 3]; list1 = list.asImmutable(); // list1[0] = 100 は UnsupportedOperationException が投げられる list[0] = 100; assert list == [100, 2, 3]; // list は mutable assert list1 == [100, 2, 3]; // list を変更すると list1 も変更される!
これ、Groovy がどうこうではなく、Java でも同じなようですね。 Java で変更不可能な List を作るには java.util.Collections#unmodifiableList(List) を用いますが、このメソッドで返される変更不可な List も、元の List の影響を受けるようです。
知らんかった・・・
もしかしたら、asSynchronized() も同じように振る舞うかも。 面倒そうなので確かめてませんが。