2009年1月24日土曜日

Iterator#remove()?

ついさっき次のような発言を見かけてショックを受けた。ええーループ中に削除なんてできないっしょ?と思ってしまった。なんといぅか、それが自分の中での常識だったのだ。だけど、あえてIteratorインターフェースが提供しているという事は…できるんだろぅな、いやどーなんだ、と思って試してみた。もし「できた」となると、過去に書いてきたコードで糞のよぅな無駄を生んできたという事実が残ってしまう。過去の事実を考えると変な汗が出るので出来て欲しく無いが、できたら出来たで今後は便利になる。
package com.shin1ogawa;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.util.*;
import java.util.Map.Entry;
import org.junit.*;

public class IteratorTest {
  private Map<Integer, String> map;
  private List<Integer> list;

  @Before
  public void setUp() {
    map = new HashMap<Integer, String>();
    for (int i = 0; i < 10; i++) {
      map.put(i, "value" + i);
    }
    assertThat(map.size(), is(10));
    
    list = new ArrayList<Integer>();
    for (int i = 0; i < 10; i++) {
      list.add(i);
    }
    assertThat(list.size(), is(10));
  }

  @Test
  public void hashMap() {
    Iterator<Entry<Integer, String>> iterator = map.entrySet().iterator();
    while (iterator.hasNext()) {
      Entry<Integer, String> next = iterator.next();
      if (next.getKey() % 2 == 1) {
        iterator.remove();
      }
    }
    System.out.println(map);
    assertThat(map.size(), is(5));
  }

  @Test(expected = ConcurrentModificationException.class)
  public void hashMap2() {
    Iterator<Entry<Integer, String>> iterator = map.entrySet().iterator();
    while (iterator.hasNext()) {
      Entry<Integer, String> next = iterator.next();
      if (next.getKey() % 2 == 1) {
        map.remove(next.getKey());
      }
    }
  }

  @Test
  public void arrayList() {
    Iterator<Integer> iterator = list.iterator();
    while (iterator.hasNext()) {
      Integer next = iterator.next();
      if (next % 2 == 1) {
        iterator.remove();
      }
    }
    assertThat(list.size(), is(5));
    System.out.println(list);
  }

  @Test(expected = ConcurrentModificationException.class)
  public void arrayList2() {
    Iterator<Integer> iterator = list.iterator();
    while (iterator.hasNext()) {
      Integer next = iterator.next();
      if (next % 2 == 1) {
        list.remove(next);
      }
    }
  }
}
うわわわ…。

2 件のコメント:

Daisuke Miyamoto さんのコメント...

UnsupportedOperationExceptionなケースが多いっすけどねw

ところで List#listIterator() って知ってます?

sss さんのコメント...

listIterator()を提供しているCollectionでは使ってますが、iterator()と何が違うか?とか考えて使っているわけではありませんw
で調べてみたら「要素の挿入・置換ができる」…まじですかー!