kagamihogeの日記

kagamihogeの日記です。

for の中でループカウンタをデクリメントをかんがえる

なんとなしにソースコード覗いてたらこんな箇所があったわけですよ。

for (int i=0; i< list.size(); i++) {
    if (isNantara(list.get(i))) {
        list.remove(i);
        i--;
    }
}

最初、何が書いてあるのかマッタク分からなかった。が、よくよく読むと、リスト中の要素からある条件を満たす要素を削除する、という処理なのが理解できた。

でまぁ、これ何が恐ろしいかっていうとですね。for の中でループカウンタを増やしたり減らしたりするのは、下手すると配列サイズオーバーしたアクセスになりかねない。まぁ Java の場合は ArrayIndexOutOfBoundsException が出るだけで済むっちゃ済むんだが……また、この例だと減らしてるだけだからいいんだけど、ループカウンタ増やしたり減らしたりすると、最悪無限ループに陥りかねない。基となるリストから要素削除してくのもちょっと恐ろしいというか……

更によろしくないのは、可読性が最悪な点。このコードで本来表現すべきことである、リストからある条件を満たす要素を抽出する、ということをこのコードから読み取るのはかなり困難である。

とまぁ、for の中でループカウンタを増減するのは百害あって一利なしだと思うわけです。

そこで Scala を思い出したわけですが。Scala のコレクションに対する処理ってたいていこう書くじゃないですか。

scala> val list = List(1, 2, 3, 4, 5, 6)
list: List[Int] = List(1, 2, 3, 4, 5, 6)

scala> list filter(_ % 2 == 0)
res0: List[Int] = List(2, 4, 6)

コレクションに対する処理を、こういう風に書けるのって色々と優位性あるなぁ、と思う次第なわけです。可読性もそうだし、副作用を防げるという意味においても。