[11] RFR: 8193128: Reduce number of implementation classes returned by List/Set/Map.of()

Claes Redestad claes.redestad at oracle.com
Thu Jan 18 17:51:51 UTC 2018


Hi,

noticed I had replied off-list to Peter by accident. Sorry for the 
unintended delay..

I think we can settle for the simplified equals (as previously outlined) 
along with an abstract hashCode to remind ourselves it needs to be 
overridden:

http://cr.openjdk.java.net/~redestad/8193128/open.06/

As for the race that's can make equals() return true when the other set 
is cleared after calling size() on it but before iterating over the 
collection, then I think that's behavior you could provoke with most of 
the non-j.u.c Set implementations in the JDK (which typically defer to 
AbstractSet::equals) - including the existing Set.of() implementation - 
so I consider it out of scope for this improvement.

Thanks!

/Claes

On 2018-01-09 13:27, Peter Levart wrote:
> Hi Claes,
>
> On 01/09/2018 02:17 AM, Claes Redestad wrote:
>> If we took it a step further we could save us the trouble of throwing 
>> and swallowing NPEs in
>> AbstractImmutableSet::equals when the other set contains null, which 
>> might be an optimization
>> in that case:
>>
>>         @Override
>>         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;
>>
>>             for (Object e : c)
>>                 if (e == null || !contains(e))
>>                     return false;
>>             return true;
>>         }
>>
>> It might be rare enough that it's not worth bothering with, though. 
>
> That's nicer in my opinion. What to do with ClassCastException from 
> contains(e)? Perhaps just document that any future implementation that 
> might throw it from contains() should also modify the equals() method 
> and catch it there.
>
> And if you already do explicit iteration over elements, you could as 
> well count them and do the size check with counted size at the end. 
> Imagine the following scenario:
>
> ConcurrentHashMap m = new ChocurrentHashMap();
> m.put(1, 1);
> m.put(2, 2);
> m.put(3, 3);
>
> Set s = Set.of("a", "b", "c");
>
> Thread 1:
>
> s.equals(m.keySet())
>
> Thread 2:
>
> m.clear();
>
> It is surprising when Thread 1 encounters 'true' as the result of the 
> equals() above which can happen when code checks for sizes separately. 
> Iterating CHM.keySet() does not provide a snapshot of the content 
> either, but counting iterated and compared elements nevertheless 
> exhibits less surprising behavior. I don't know if it matters though.
>
> Regards, Peter
>



More information about the core-libs-dev mailing list