JDK-4759223 : (coll) ArrayList constructor should assign result of Collection.toArray(Object[])
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Affected Version: 1.4.1
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86
  • Submitted: 2002-10-07
  • Updated: 2018-12-19
  • Resolved: 2006-09-27
Related Reports
Duplicate :  
Description
Name: gm110360			Date: 10/07/2002


FULL PRODUCT VERSION :
java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21)
Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode)

Also:

java version "1.3.1_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_03-b03)
Java HotSpot(TM) Client VM (build 1.3.1_03-b03, mixed mode)

FULL OPERATING SYSTEM VERSION :

Linux 2.4.19-gentoo-r9 running on an AMD XP.

ADDITIONAL OPERATING SYSTEMS :

This is an issue with the code in the standard Java
libraries. I have not checked, but it should be operating
system independent.

A DESCRIPTION OF THE PROBLEM :
ArrayList constructor should assign result of
Collection.toArray(Object[])

I would like to suggest a change to one of ArrayList's
constructors. This improvement would solve a problem for me,
but it would also eliminate a minor race condition.

The change is simple enough that it might be worth making,
despite its limited benefit.


At the moment one of the constructors for ArrayList looks
like this:

    public ArrayList(Collection c) {
        size = c.size();
        // Allow 10% room for growth
        elementData = new Object[
                     
(int)Math.min((size*110L)/100,Integer.MAX_VALUE)];
        c.toArray(elementData);
    }

I think that the last line should be changed to:

        elementData = c.toArray(elementData);


Usually, the behaviour of the two pieces of code would be
just the same. However the change would allow it to cope
with two situations. As I mentioned earlier, one is a minor
race condition. The other is more difficult to deal with, is
only likely to affect me.

[Situation 1] The size of the collection changes.

If the Collection's size changes (by over 10%) between the
call to c.size() and the call to c.toArray() then the
changed code will work correctly. The original code will
populate the ArrayList with a truncated version of the
Collection.

This fixes a small problem, but I think it is worth making.
This race condition might not look particularly important,
but an ArrayList is often used (by me, anyway) to take a
'snapshot' of a synchronized List. It would be nice if the
operation was atomic.

[Situation 2] When the Collection is a 'remote' object.

In my application I am wrapping Java's collections so they
can work natively in the Ozone ODB
(http://www.ozone-db.org/). In this application, the
toArray(Object[]) method is sometimes called on a proxy
Collection object.

The proxy Collection operates just like a normal Collection
except it de/serializes the arguments and return values.
This means that using the array as an in/out variable
doesn't work. If I try to construct an ArrayList from a
proxy Collection I just get a List of nulls.


In conclusion, this change would make the code more robust
under unusual conditions. It would impose a small
performance cost (an extra assignment), but I think this is
justified. The real cost is the cost of retesting, which I
can't really comment on.

REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER WORKAROUND :
I am describing a flaw in the code rather than its
behaviour, so there is no real workaround. However, there is
a workaround for the examples I use in each the situations I
describe.

[Situation 1] Getting an atomic copy of a synchronized list

Arrays.asList(synchronizedList.toArray())

[Situation 2] Getting a copy of a 'remote' list

Arrays.asList(remoteList.toArray())
(Review ID: 165338) 
======================================================================

Comments
EVALUATION Situation 1 was fixed by 6347106: (coll) Make ArrayList(Collection) more threadsafe I don't quite understand Situation 2. It sounds like a proxy collection simply doesn't properly implement the Collection interface, and ArrayList should not try to support such non-conformant implementations. So I will ignore Situation 2, and simply close this as a dup of 6347106
27-09-2006