HashSet/TreeSet could do what ConcurrentHashMap/ConcurrentSkipListSet do by using the "this contains that and that contains this" logic.
Comparator<String> cc = String.CASE_INSENSITIVE_ORDER; Set<String> s1 = new ConcurrentHashMap<String, Object>().keySet(""); Set<String> s2 = new ConcurrentSkipListSet<>(cc); s1.add("hello"); s2.add("Hello"); System.out.println(s1.equals(s2)); System.out.println(s2.equals(s1)); System.out.println(s1.hashCode() == s2.hashCode()); === false false false ________________________________________ From: core-libs-dev <core-libs-dev-boun...@openjdk.java.net> on behalf of Alan Snyder <javali...@cbfiddle.com> Sent: Tuesday, May 12, 2020 11:27 AM To: Stuart Marks Cc: core-libs-dev Subject: Re: RFR [15] 6394757: rev2: AbstractSet.removeAll semantics are surprisingly dependent on relative sizes > On May 8, 2020, at 1:49 PM, Stuart Marks <stuart.ma...@oracle.com> wrote: > > The containsAll() and equals() methods both use the membership contract of > the receiver, not the argument. Unfortunately, the equals() specification > says, > > Returns true if the specified object is also a set, the two sets have the > same size, and every member of the specified set is contained in this set > (or equivalently, every member of this set is contained in the specified > set). > > As should be clear from this discussion, the "equivalently" clause is > incorrect -- another spec bug. Changing Set.equals() in this way would make Set inconsistent with Object. Do you really think that is a good idea? Comparator<String> cc = (a, b) -> a.compareToIgnoreCase(b); Set<String> s1 = new HashSet<>(); Set<String> s2 = new TreeSet<>(cc); s1.add("hello"); s2.add("Hello"); s1.equals(s2) -> false s2.equals(s1) -> true s1.hashCode() == s2.hashCode() -> false