FastArrayListはforEach()に対応していない
OpenJDK11で、Apache Commons Collections 3系に含まれるFastArrayListに対して、forEach()を行うと処理が行われない。
List<String> list = new FastArrayList(); list.add("aaa"); list.add("bbb"); list.add("ccc"); StringBuilder sb = new StringBuilder(); list.forEach(e -> sb.append(e)); // xxが出力される System.out.println("x" + sb.toString() + "x");
原因
FastArrayListはforEach()をオーバーライドしていないので、親であるArrayListのforEach()が実行される。
@Override public void forEach(Consumer<? super E> action) { Objects.requireNonNull(action); final int expectedModCount = modCount; final Object[] es = elementData; final int size = this.size; for (int i = 0; modCount == expectedModCount && i < size; i++) action.accept(elementAt(es, i)); if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
ループ条件のmodCountはAbstractListで宣言されている。
protected transient int modCount = 0;
また、sizeはArrayListで宣言されている。
private int size;
これらはArrayList#add(E)ではインクリメントされるが、FastArrayList#add(Object)ではインクリメントされない。(sizeはアクセスできないし)
対処
匿名クラスでforEach()をオーバーライドする。
List<String> list = new FastArrayList() { public void forEach(Consumer action) { Objects.requireNonNull(action); for (Object t : this) { action.accept(t); } }; }; list.add("aaa"); list.add("bbb"); list.add("ccc"); StringBuilder sb = new StringBuilder(); list.forEach(e -> sb.append(e)); // xaaabbbcccxが出力される System.out.println("x" + sb.toString() + "x");