倭マン's BLOG

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

Groovy in Addiction (11) : Groovy のコレクションで注意するべきこと

今回はGroovy のコレクションで注意するべきことについて。 『Groovyイン・アクション』Chapter4 を参考にしています(一覧)。

Groovyイン・アクション

Groovyイン・アクション

コピーと変更のセマンティクス


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() も同じように振る舞うかも。 面倒そうなので確かめてませんが。