HashMap implementations and Integer specializations

Martin Buchholz martinrb at google.com
Mon Jun 9 18:39:15 UTC 2008


Charlie,

Test case code is different from regular code
in that bad practice is often a good idea.
People should know better than to "fix" test cases
using their IDE.

But I added this comment:

        // This code intentionally uses the denigrated constructors
        // that are guaranteed to return a unique object!

Martin

On Mon, Jun 9, 2008 at 11:26 AM, charlie hunt <charlie.hunt at sun.com> wrote:
> Martin,
>
> I'm rather shocked at your response!
>
> Consider for example, there's a very popular tool out their that integrates
> very well into NetBeans  IDE and Eclipse IDE which suggests changing all
> 'new Integer(), new Long()' calls into 'Integer.valueOf() & Long.valueOf()'.
>  Take a quick look at how new Integer() contrasts with Integer.valueOf().
>
> Suppose in the future as Martin moves on to bigger and better things beyond
> OpenJDK and a future maintainer looks at your test case and updates it to
> use Integer.valueOf() and Long.valueOf() as result of such a tool mentioned
> above.   Should that happen, I don't think your test case would test what it
> was intended to test.
>
> Would not your test case be improved by choosing values well outside the
> values contained in the IntegerCache & LongCache?
>
> charlie ...
>
> Martin Buchholz wrote:
>>
>> Charlie,
>>
>> Hotspot engineers throughout the ages
>> have been tempted to optimize away
>> object identity semantics of Integer and String,
>> but I'm pretty sure that for e.g. new Integer(x)
>> and new String(y) hotspot will certainly continue
>> to return _new_ objects (unless of course
>> the application can be proven to not tell the
>> difference), and there are sufficient
>> regression tests to keep all of us in line.
>>
>> Martin
>>
>> On Mon, Jun 9, 2008 at 7:57 AM, charlie hunt <charlie.hunt at sun.com> wrote:
>>
>>>
>>> wrt the Integer & Long values you use in your test case ...
>>>
>>> You might consider using larger Integer & Long values, ones that lie
>>> outside
>>> the range of Integer.IntegerCache & Long.LongCache to avoid any potential
>>> confusion about whether the values you are putting into the Map might get
>>> grabbed from the IntegerCache or LongCache via some "magic" of the
>>> HotSpot
>>> compiler, i.e it's conceivable a call to 'new Integer()' could be
>>> transformed into Integer.valueOf()'.
>>>
>>> charlie ...
>>>
>>> Martin Buchholz wrote:
>>>
>>>>
>>>> JavaOne 2008 technical session PDFs are now available
>>>>
>>>>
>>>>
>>>> http://developers.sun.com/learning/javaoneonline/j1online.jsp?track=javase&yr=2008
>>>>
>>>> I was surprised to discover a discussion of
>>>> HashMap optimization at the JavaOne talk
>>>> http://developers.sun.com/learning/javaoneonline/2008/pdf/TS-6434.pdf
>>>>
>>>> Did I miss an announcement of that?
>>>>
>>>> A comment on that talk:
>>>>
>>>> It is easy to make the mistake of thinking that HashMap does not
>>>> have to store the actual Integer key in the call to put.
>>>> Unfortunately, Java's evil semantics (everything is an Object,
>>>> everything is a Lock, everything has an Identity) require
>>>> that the exact same objects inserted into a HashMap can be
>>>> removed later.  This means that specialized submaps will have
>>>> a harder time optimizing for footprint.  (I do think the
>>>> algorithm presented in the talk is correct, since the front cache
>>>> is likely only used for get(), and not, e.g. for entrySet().iterator())
>>>>
>>>> I intend to check in a test case modification that will ensure
>>>> that future optimizations do not violate the current compatibility
>>>> guarantees.
>>>>
>>>> diff --git a/test/java/util/Collection/MOAT.java
>>>> b/test/java/util/Collection/MOAT.java
>>>> --- a/test/java/util/Collection/MOAT.java
>>>> +++ b/test/java/util/Collection/MOAT.java
>>>> @@ -544,6 +544,27 @@ public class MOAT {
>>>>        check(m.size() != 0 ^ m.isEmpty());
>>>>    }
>>>>
>>>> +    private static void testPutPreversesObjectIdentity(Map<?,?> m,
>>>> +                                                       Object key,
>>>> +                                                       Object val) {
>>>> +        try {
>>>> +            Map<Object,Object> m2 = m.getClass().newInstance();
>>>> +            m2.put(key, val);
>>>> +            Map.Entry<Object,Object> e =
>>>> m2.entrySet().iterator().next();
>>>> +            check(e.getKey()   == key);
>>>> +            check(e.getValue() == val);
>>>> +            check(m2.keySet().iterator().next() == key);
>>>> +            check(m2.values().iterator().next() == val);
>>>> +        } catch (Throwable t) { unexpected(t); }
>>>> +    }
>>>> +
>>>> +    private static void testPutPreversesObjectIdentity(Map<?,?> m) {
>>>> +        testPutPreversesObjectIdentity(m, new Integer(42),  new
>>>> Integer(43));
>>>> +        testPutPreversesObjectIdentity(m, new Long(42L),    new
>>>> Long(43L));
>>>> +        testPutPreversesObjectIdentity(m, new Double(42.0), new
>>>> Double(43.0));
>>>> +        testPutPreversesObjectIdentity(m, new String("42"), new
>>>> String("43"));
>>>> +    }
>>>> +
>>>>    private static void testMap(Map<Integer,Integer> m) {
>>>>        System.out.println("\n==> " + m.getClass().getName());
>>>>
>>>> @@ -572,6 +593,7 @@ public class MOAT {
>>>>        }
>>>>
>>>>        if (supportsPut(m)) {
>>>> +            testPutPreversesObjectIdentity(m);
>>>>            try {
>>>>                check(m.put(3333, 77777) == null);
>>>>                check(m.put(9134, 74982) == null);
>>>>
>>>>
>>>
>>> --
>>>
>>> Charlie Hunt
>>> Java Performance Engineer
>>>
>>> <http://java.sun.com/docs/performance/>
>>>
>>>
>>>
>
> --
>
> Charlie Hunt
> Java Performance Engineer
>
> <http://java.sun.com/docs/performance/>
>
>



More information about the core-libs-dev mailing list