Immutable.listCopyfOf throws ArrayIndexOutOfBoundsException

guava, java

Solution

It seems to be an issue with the toArray() method of your collection. You say you are using a ConcurrentLinkedQueue, but your stack trace shows `AbstractCollection.toArray`. This seems fishy since `java.util.ConcurrentLinkedQueue` has its own toArray implementation.

What collection are you really using? I suspect that collection and not `ImmutableList`.

Problem

I'm using google gauva version 11.0.1 and have this piece of code: ``` ImmutableList.copyOf(items); ``` Where items is a ConcurrentLinkedQueue. I occasionally see this error: ``` 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) ``` Given the issue lies entirely within the guava library, does anyone know why? Update based on correct answer below Thanks for the help from wolfcastle, I managed to reproduce the issue in isolation, outside of my application. ``` 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); ``` Running this produces the following everytime: ``` 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) ``` To solve in my application, I found a number of options. Moving away from Collections2 By switching from Collections2.transform to Iterables.transform, the problem goes away. Moving away from Java 1.5 Whilst this wasn't possible in my situation, I tried it with Java 1.6 and Java 1.7 and the problem goes away. I suspect this is due to a change in implementation in AbstractCollection.toArray() from 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; } ``` Copying the ConcurrentLinkedQueue first Performing a transform on a non-thread safe Collection is obviously far from ideal. If for some reason I had to stay with Collections2.transform, I can solve the issue by taking a copy of the items collection first.

Original source