Immutable.listCopyfOf抛出ArrayIndexOutOfBoundsException

时间:2013-08-22 15:51:43

标签: java guava

我正在使用google gauva版本11.0.1并拥有这段代码:

ImmutableList.copyOf(items);

其中items是ConcurrentLinkedQueue。我偶尔会看到这个错误:

java.lang.ArrayIndexOutOfBoundsException: 10
at java.util.AbstractCollection.toArray(AbstractCollection.java:126)
at com.google.common.collect.ImmutableList.copyFromCollection(ImmutableList.java:278)
at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:247)
at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:217)

鉴于问题完全在番石榴库中,有谁知道为什么?

根据以下正确答案进行更新

感谢wolfcastle的帮助,我设法在我的申请之外单独重现了这个问题。

final int itemsToPut = 30000;

final ConcurrentLinkedQueue<Integer> items = new ConcurrentLinkedQueue<Integer>();
new Thread(new Runnable() {
    public void run() {
       for (int i = 0; i < itemsToPut; i++) {
           items.add(i);
           }
    }
}, "putter-thread").start();
final Iterable<String> transformed = Collections2.transform(items, new Function<Integer, String>() {
    public String apply(Integer integer) {
        return "foo-" + integer;
    }
});
ImmutableList.copyOf(transformed);

每次运行此命令会产生以下结果:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 21480
    at java.util.AbstractCollection.toArray(AbstractCollection.java:126)
    at com.google.common.collect.ImmutableList.copyFromCollection(ImmutableList.java:278)
    at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:247)
    at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:217)

要在我的申请中解决,我找到了很多选择。

远离Collections2

从Collections2.transform切换到Iterables.transform,问题就消失了。

远离Java 1.5

虽然在我的情况下这是不可能的,但我尝试使用Java 1.6和Java 1.7,问题就消失了。我怀疑这是由于AbstractCollection.toArray()中1.5的实现发生了变化:

1.5

public Object[] toArray() {
    Object[] result = new Object[size()];
    Iterator<E> e = iterator();
    for (int i=0; e.hasNext(); i++)
        result[i] = e.next();
    return result;
}

1.6

public Object[] toArray() {
    // Estimate size of array; be prepared to see more or fewer elements
    Object[] r = new Object[size()];
        Iterator<E> it = iterator();
    for (int i = 0; i < r.length; i++) {
        if (! it.hasNext()) // fewer elements than expected
        return Arrays.copyOf(r, i);
        r[i] = it.next();
    }
    return it.hasNext() ? finishToArray(r, it) : r;
}

首先复制ConcurrentLinkedQueue

对非线程安全集合执行转换显然远非理想。如果由于某种原因我不得不继续使用Collections2.transform,我可以通过首先获取items集合的副本来解决问题。

2 个答案:

答案 0 :(得分:6)

这似乎是您的集合的toArray()方法的问题。您说您正在使用ConcurrentLinkedQueue,但您的堆栈跟踪显示AbstractCollection.toArray。这看起来很可疑,因为java.util.ConcurrentLinkedQueue有自己的toArray实现。

你真正使用什么系列?我怀疑这个集合而不是ImmutableList

答案 1 :(得分:0)

在执行copyOf()期间,List的大小是否可能发生变化?

如果在方法开头检查了尺寸,但ConcurrentLinkedQueue尺寸增加了,则会产生ArrayIndexOutOfBoundsException