Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 6576056
Votes 0
Synopsis (coll) AbstractSet/AbstractMap equals() method is asymmetric with large sets/maps
Category java:classes_util
Reported Against
Release Fixed
State 5-Cause Known, bug
Priority: 4-Low
Related Bugs
Submit Date 02-JUL-2007
Description
FULL PRODUCT VERSION :
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)


EXTRA RELEVANT SYSTEM CONFIGURATION :
None...platform-independent problem

A DESCRIPTION OF THE PROBLEM :
The equals() method is flawed for extremely large sets (> Integer.MAX_VALUE elements).

The size() contract for Collections is this:

    /**
     * Returns the number of elements in this collection.  If this collection
     * contains more than <tt>Integer.MAX_VALUE </tt> elements, returns
     * <tt>Integer.MAX_VALUE</tt>.
     *
     * @return the number of elements in this collection
     */
    int size();

but the AbstractSet equals method does this:

    public boolean equals(Object o) {
    if (o == this)
        return true;

    if (!(o instanceof Set))
        return false;
    Collection c = (Collection) o;
    if (c.size() != size())
        return false;
        try {
            return containsAll(c);
        } catch (ClassCastException unused)   {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }
    }

If I have two Sets, each with at least MAX_VALUE elements, and one is a proper superset of the other, then equals is asymmetric.

So, if:
    set1 = {0, .., MAX_INT} and set2 = {1, ..., MAX_INT}
then:
    set1.equals(set2)
but
   !set2.equals(set1)

Here's a fix:

  public boolean equals(Object o) {
    if (o == this)
      return true;

    if (!(o instanceof Set)) {
      return false;
    }
    @SuppressWarnings("unchecked") // o instanceof Set ==> o is a Collection
    Collection<?> c = (Collection) o;
    int cSize = c.size();
    if (cSize != size()) {
      return false;
    }
    try {
      boolean result = containsAll(c);
      if (cSize == Integer.MAX_VALUE) {
        result &= c.containsAll(this);
      }
      return result;
    } catch (ClassCastException unused)   {
      return false;
    } catch (NullPointerException unused) {
      return false;
    }
  }

It appears that AbstractMap has the same problem.

Just to head off questions like "What are you doing, creating sets with more than MAX_INT elements!?!!?" ...I'm creating sets that generate their elements dynamically, so I'm not really allocating MAX_INT objects.  :-)

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See description.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect equals() to always be symmetric.
ACTUAL -
equals() is asymmetric under the conditions as per the Description field, above.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
No error message...just incorrect behaviour.

REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER SUBMITTED WORKAROUND :
Subclasses of AbstractSet / AbstractMap can override equals() with the fix given in the Description.
Posted Date : 2007-07-02 10:48:18.0
Work Around
N/A
Evaluation
Support for collections with more than Integer.MAX_VALUE elements is weak at best.
Posted Date : 2007-07-02 17:40:46.0
Comments
  
  Include a link with my name & email   

Submitted On 17-OCT-2007
Agreed vehemently.  I call these VLC's, very large collections, and there's a long list of things that fall down badly in their presence.  They should be discouraged.


Submitted On 07-MAR-2008
Jason-Mehrens
In terms of any class that implements the Collection interface it would be legal to implement all the methods
by doing a toArray conversion first.  By contract, since the longest length of an array is Integer.MAX_VALUE the largest size for a collection is Integer.MAX_VALUE.

VLCs should really be treated as an java.lang.Iterable and not a collection.  There are already existing RFEs asking for better Iterable support.



PLEASE NOTE: JDK6 is formerly known as Project Mustang