JDK-4459681 : HashSet.contains DOCUMENTATION, et. al. not precise
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Affected Version: 1.3.1
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: generic
  • CPU: generic
  • Submitted: 2001-05-16
  • Updated: 2021-03-03
  • Resolved: 2001-05-16
Description

Name: bsC130419			Date: 05/16/2001


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

The documentation for HashSet, et al, is not precise enough.

For instance,

HashSet.contains(Object o) says:
"Returns true if this set contains the specified element.
Specified by:
   contains in interface Set"

As this is a relatively abstract description, one reads Set.contains which says:
"...More formally, returns true if and only if this set contains an element e
such that ((o == null) ? (e == null) : o.equals(e))"

But this is not true, If two elements of a HashSet do not map to the same
bucket equals is never called.

Documentation for HashSet.contains(Object o) et al, should be embellished to
say:
"Returns true if this set contains the specified element. More formally,
returns true if and only if this set contains an element e such that e.hashCode
() == o.hashCode(), and ((o == null) ? (e == null) : o.equals(e))"
-----------------------------------------------------------------------

Here is a sample program exhibiting the difference. As is, contains will return
false. If you uncomment the hashCode function, contains will return true.

import java.util.*;

public class ContainsDoc
{
    public static void main( String[] args )
    {
        HashSet hs = new HashSet();
        
        Data d1 = new Data( "Hello" );
        Data d2 = new Data( "Hello" );
        
        hs.add( d1 );
        if (hs.contains( d2 ))
            System.out.println("Found d2");
        else
            System.out.println("Did not find d2");
        System.exit(0);
    }
}

class Data
{
    String m_Info;
    
    public Data( String info )
    {
        m_Info = info;
    }
    
    public boolean equals( Object o )
    {
        System.out.println("Equals called on " + toString() );
        if (o instanceof Data)
        {
            return m_Info.equals( ((Data) o).m_Info );
        }
        
        return false;
    }
    
/*
    public int hashCode()
    {
        return m_Info.hashCode();
    }
 */
}
(Review ID: 124507) 
======================================================================

Comments
WORK AROUND Name: bsC130419 Date: 05/16/2001 Use hashCode(). There is nothing wrong with the JRE. The documentation is just not precise enough. ======================================================================
11-06-2004

EVALUATION If two elements do not map to the same bucket, then their hashcodes are unequal, and as per the contract between hashcode and equals, two items are not equal if their hashcodes are not equal. It would be redundant to check the equality of two elements that do not have the same hashcode. Similiarly no check for the equality of hashcodes is needed since if two elements are equal they must have the same hashcode. michael.mccloskey@eng 2001-05-16
16-05-2001