How to guarantee the behavior of Set.removeAll with different type of sets?










2














I have a problem with the HashSet and TreeSet manipulation.
Here is a simple JUnit 4 test explaining my problem :



import java.util.HashSet;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicReference;

import org.junit.Assert;
import org.junit.Test;

public class TreeSetTest<T>

@Test
public void test()
final HashSet<Object> set1 = new HashSet<>();
final TreeSet<Object> set2 = new TreeSet<>((a, b) -> a.toString().compareTo(b.toString()));
Assert.assertEquals(0, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.add(new AtomicReference<>("A"));
set1.add(new AtomicReference<>("B"));
set1.add(new AtomicReference<>("C"));
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set2.add(new AtomicReference<>("A"));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(1, set2.size());
set2.add(new AtomicReference<>("B"));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(2, set2.size());
set2.add(new AtomicReference<>("C"));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // Error Everything has been removed and size is now 0
Assert.assertEquals(3, set2.size());





When removing all elements of set2 from set1, I'm expecting to use the equality comparator of set1 which is the case as long as set2 has a size less than the one of set1 but if the size of set2 is greater or equals to the size of set1, the comparison is made from the set2.



This is very bad for me because it makes the program unpredictable.



I think it can be considered as a bug in the java implementation but my concern is:
How can I guarantee the expected behavior without rewritting eveything?



Edit 1 after @FedericoPeraltaSchaffner comment:



AtomicReference was just for providing a simple example. In fact, I am using a class which is final from a library so I cannot improve it easily.
But even considering a valid class implementing correctly hashCode and equals, my problem remains. Consider this now :



package fr.ncenerar.so;

import java.util.HashSet;
import java.util.TreeSet;

import org.junit.Assert;
import org.junit.Test;

public class TreeSetTest<T>

public static class MyObj
private final int value1;
private final int value2;

public MyObj(final int v1, final int v2)
super();
this.value1 = v1;
this.value2 = v2;


public int getValue1()
return this.value1;


public int getValue2()
return this.value2;


@Override
public int hashCode()
final int prime = 31;
int result = 1;
result = prime * result + this.value1;
result = prime * result + this.value2;
return result;


@Override
public boolean equals(final Object obj)
if (this == obj)
return true;

if (obj == null)
return false;

if (this.getClass() != obj.getClass())
return false;

final MyObj other = (MyObj) obj;
if (this.value1 != other.value1)
return false;

if (this.value2 != other.value2)
return false;

return true;



@Test
public void test()
final HashSet<MyObj> set1 = new HashSet<>();
final TreeSet<MyObj> set2 = new TreeSet<>((a, b) -> a.getValue1() - b.getValue1());
Assert.assertEquals(0, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.add(new MyObj(0, 0));
set1.add(new MyObj(1, 1));
set1.add(new MyObj(2, 2));
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set2.add(new MyObj(0, 1));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(1, set2.size());
set2.add(new MyObj(1, 2));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(2, set2.size());
set2.add(new MyObj(2, 3));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // Error Everything has been removed
Assert.assertEquals(3, set2.size());





The problem is still there and MyObj implementation is correct. The problem comes from the fact that I am using the objects from two differents aspects. In one set, I want to keep one instance of each objects based on their equality (as in equals method of the object) and in another set, I want a subset of the first set in which for each value1, I want to keep only the firstly inserted element.



Using a TreeSet seemed valid.



Edit 2:



My bad, I missed that part of the TreeSet documentation:




Note that the ordering maintained by a set (whether or not an
explicit comparator is provided) must be consistent with equals if it
is to correctly implement the Set interface. (See Comparable or
Comparator for a precise definition of consistent withequals.) This is
so because the Set interface is defined interms of the equals
operation, but a TreeSet instance performs all element comparisons
using its compareTo (or compare) method, so two elements that are
deemed equal by this method are, from the standpoint of the set, equal.
The behavior of a set is well-defined even if its ordering is
inconsistent with equals; it just fails to obey the general contract of
the Set interface.




If I understand correctly, I can use a TreeSet for my purpose but can't expect it to behave like I want it to.



Thank you all for your help.










share|improve this question























  • @FedericoPeraltaSchaffner Thank you for your comment. I updated my question to add some info.
    – ncenerar
    Nov 12 '18 at 16:50










  • can't you make the comparator passed to the treeset consistent with equals? I.e. make it return 0 only if the elements are equal as per the equals method
    – Federico Peralta Schaffner
    Nov 12 '18 at 16:56











  • @FedericoPeraltaSchaffner Unfortunately, no. In fact, the library I am using creates new instances (different from an equals point of view) for objects that are in reality equal (from my point of view).
    – ncenerar
    Nov 12 '18 at 17:32















2














I have a problem with the HashSet and TreeSet manipulation.
Here is a simple JUnit 4 test explaining my problem :



import java.util.HashSet;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicReference;

import org.junit.Assert;
import org.junit.Test;

public class TreeSetTest<T>

@Test
public void test()
final HashSet<Object> set1 = new HashSet<>();
final TreeSet<Object> set2 = new TreeSet<>((a, b) -> a.toString().compareTo(b.toString()));
Assert.assertEquals(0, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.add(new AtomicReference<>("A"));
set1.add(new AtomicReference<>("B"));
set1.add(new AtomicReference<>("C"));
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set2.add(new AtomicReference<>("A"));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(1, set2.size());
set2.add(new AtomicReference<>("B"));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(2, set2.size());
set2.add(new AtomicReference<>("C"));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // Error Everything has been removed and size is now 0
Assert.assertEquals(3, set2.size());





When removing all elements of set2 from set1, I'm expecting to use the equality comparator of set1 which is the case as long as set2 has a size less than the one of set1 but if the size of set2 is greater or equals to the size of set1, the comparison is made from the set2.



This is very bad for me because it makes the program unpredictable.



I think it can be considered as a bug in the java implementation but my concern is:
How can I guarantee the expected behavior without rewritting eveything?



Edit 1 after @FedericoPeraltaSchaffner comment:



AtomicReference was just for providing a simple example. In fact, I am using a class which is final from a library so I cannot improve it easily.
But even considering a valid class implementing correctly hashCode and equals, my problem remains. Consider this now :



package fr.ncenerar.so;

import java.util.HashSet;
import java.util.TreeSet;

import org.junit.Assert;
import org.junit.Test;

public class TreeSetTest<T>

public static class MyObj
private final int value1;
private final int value2;

public MyObj(final int v1, final int v2)
super();
this.value1 = v1;
this.value2 = v2;


public int getValue1()
return this.value1;


public int getValue2()
return this.value2;


@Override
public int hashCode()
final int prime = 31;
int result = 1;
result = prime * result + this.value1;
result = prime * result + this.value2;
return result;


@Override
public boolean equals(final Object obj)
if (this == obj)
return true;

if (obj == null)
return false;

if (this.getClass() != obj.getClass())
return false;

final MyObj other = (MyObj) obj;
if (this.value1 != other.value1)
return false;

if (this.value2 != other.value2)
return false;

return true;



@Test
public void test()
final HashSet<MyObj> set1 = new HashSet<>();
final TreeSet<MyObj> set2 = new TreeSet<>((a, b) -> a.getValue1() - b.getValue1());
Assert.assertEquals(0, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.add(new MyObj(0, 0));
set1.add(new MyObj(1, 1));
set1.add(new MyObj(2, 2));
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set2.add(new MyObj(0, 1));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(1, set2.size());
set2.add(new MyObj(1, 2));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(2, set2.size());
set2.add(new MyObj(2, 3));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // Error Everything has been removed
Assert.assertEquals(3, set2.size());





The problem is still there and MyObj implementation is correct. The problem comes from the fact that I am using the objects from two differents aspects. In one set, I want to keep one instance of each objects based on their equality (as in equals method of the object) and in another set, I want a subset of the first set in which for each value1, I want to keep only the firstly inserted element.



Using a TreeSet seemed valid.



Edit 2:



My bad, I missed that part of the TreeSet documentation:




Note that the ordering maintained by a set (whether or not an
explicit comparator is provided) must be consistent with equals if it
is to correctly implement the Set interface. (See Comparable or
Comparator for a precise definition of consistent withequals.) This is
so because the Set interface is defined interms of the equals
operation, but a TreeSet instance performs all element comparisons
using its compareTo (or compare) method, so two elements that are
deemed equal by this method are, from the standpoint of the set, equal.
The behavior of a set is well-defined even if its ordering is
inconsistent with equals; it just fails to obey the general contract of
the Set interface.




If I understand correctly, I can use a TreeSet for my purpose but can't expect it to behave like I want it to.



Thank you all for your help.










share|improve this question























  • @FedericoPeraltaSchaffner Thank you for your comment. I updated my question to add some info.
    – ncenerar
    Nov 12 '18 at 16:50










  • can't you make the comparator passed to the treeset consistent with equals? I.e. make it return 0 only if the elements are equal as per the equals method
    – Federico Peralta Schaffner
    Nov 12 '18 at 16:56











  • @FedericoPeraltaSchaffner Unfortunately, no. In fact, the library I am using creates new instances (different from an equals point of view) for objects that are in reality equal (from my point of view).
    – ncenerar
    Nov 12 '18 at 17:32













2












2








2







I have a problem with the HashSet and TreeSet manipulation.
Here is a simple JUnit 4 test explaining my problem :



import java.util.HashSet;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicReference;

import org.junit.Assert;
import org.junit.Test;

public class TreeSetTest<T>

@Test
public void test()
final HashSet<Object> set1 = new HashSet<>();
final TreeSet<Object> set2 = new TreeSet<>((a, b) -> a.toString().compareTo(b.toString()));
Assert.assertEquals(0, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.add(new AtomicReference<>("A"));
set1.add(new AtomicReference<>("B"));
set1.add(new AtomicReference<>("C"));
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set2.add(new AtomicReference<>("A"));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(1, set2.size());
set2.add(new AtomicReference<>("B"));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(2, set2.size());
set2.add(new AtomicReference<>("C"));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // Error Everything has been removed and size is now 0
Assert.assertEquals(3, set2.size());





When removing all elements of set2 from set1, I'm expecting to use the equality comparator of set1 which is the case as long as set2 has a size less than the one of set1 but if the size of set2 is greater or equals to the size of set1, the comparison is made from the set2.



This is very bad for me because it makes the program unpredictable.



I think it can be considered as a bug in the java implementation but my concern is:
How can I guarantee the expected behavior without rewritting eveything?



Edit 1 after @FedericoPeraltaSchaffner comment:



AtomicReference was just for providing a simple example. In fact, I am using a class which is final from a library so I cannot improve it easily.
But even considering a valid class implementing correctly hashCode and equals, my problem remains. Consider this now :



package fr.ncenerar.so;

import java.util.HashSet;
import java.util.TreeSet;

import org.junit.Assert;
import org.junit.Test;

public class TreeSetTest<T>

public static class MyObj
private final int value1;
private final int value2;

public MyObj(final int v1, final int v2)
super();
this.value1 = v1;
this.value2 = v2;


public int getValue1()
return this.value1;


public int getValue2()
return this.value2;


@Override
public int hashCode()
final int prime = 31;
int result = 1;
result = prime * result + this.value1;
result = prime * result + this.value2;
return result;


@Override
public boolean equals(final Object obj)
if (this == obj)
return true;

if (obj == null)
return false;

if (this.getClass() != obj.getClass())
return false;

final MyObj other = (MyObj) obj;
if (this.value1 != other.value1)
return false;

if (this.value2 != other.value2)
return false;

return true;



@Test
public void test()
final HashSet<MyObj> set1 = new HashSet<>();
final TreeSet<MyObj> set2 = new TreeSet<>((a, b) -> a.getValue1() - b.getValue1());
Assert.assertEquals(0, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.add(new MyObj(0, 0));
set1.add(new MyObj(1, 1));
set1.add(new MyObj(2, 2));
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set2.add(new MyObj(0, 1));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(1, set2.size());
set2.add(new MyObj(1, 2));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(2, set2.size());
set2.add(new MyObj(2, 3));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // Error Everything has been removed
Assert.assertEquals(3, set2.size());





The problem is still there and MyObj implementation is correct. The problem comes from the fact that I am using the objects from two differents aspects. In one set, I want to keep one instance of each objects based on their equality (as in equals method of the object) and in another set, I want a subset of the first set in which for each value1, I want to keep only the firstly inserted element.



Using a TreeSet seemed valid.



Edit 2:



My bad, I missed that part of the TreeSet documentation:




Note that the ordering maintained by a set (whether or not an
explicit comparator is provided) must be consistent with equals if it
is to correctly implement the Set interface. (See Comparable or
Comparator for a precise definition of consistent withequals.) This is
so because the Set interface is defined interms of the equals
operation, but a TreeSet instance performs all element comparisons
using its compareTo (or compare) method, so two elements that are
deemed equal by this method are, from the standpoint of the set, equal.
The behavior of a set is well-defined even if its ordering is
inconsistent with equals; it just fails to obey the general contract of
the Set interface.




If I understand correctly, I can use a TreeSet for my purpose but can't expect it to behave like I want it to.



Thank you all for your help.










share|improve this question















I have a problem with the HashSet and TreeSet manipulation.
Here is a simple JUnit 4 test explaining my problem :



import java.util.HashSet;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicReference;

import org.junit.Assert;
import org.junit.Test;

public class TreeSetTest<T>

@Test
public void test()
final HashSet<Object> set1 = new HashSet<>();
final TreeSet<Object> set2 = new TreeSet<>((a, b) -> a.toString().compareTo(b.toString()));
Assert.assertEquals(0, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.add(new AtomicReference<>("A"));
set1.add(new AtomicReference<>("B"));
set1.add(new AtomicReference<>("C"));
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set2.add(new AtomicReference<>("A"));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(1, set2.size());
set2.add(new AtomicReference<>("B"));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(2, set2.size());
set2.add(new AtomicReference<>("C"));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // Error Everything has been removed and size is now 0
Assert.assertEquals(3, set2.size());





When removing all elements of set2 from set1, I'm expecting to use the equality comparator of set1 which is the case as long as set2 has a size less than the one of set1 but if the size of set2 is greater or equals to the size of set1, the comparison is made from the set2.



This is very bad for me because it makes the program unpredictable.



I think it can be considered as a bug in the java implementation but my concern is:
How can I guarantee the expected behavior without rewritting eveything?



Edit 1 after @FedericoPeraltaSchaffner comment:



AtomicReference was just for providing a simple example. In fact, I am using a class which is final from a library so I cannot improve it easily.
But even considering a valid class implementing correctly hashCode and equals, my problem remains. Consider this now :



package fr.ncenerar.so;

import java.util.HashSet;
import java.util.TreeSet;

import org.junit.Assert;
import org.junit.Test;

public class TreeSetTest<T>

public static class MyObj
private final int value1;
private final int value2;

public MyObj(final int v1, final int v2)
super();
this.value1 = v1;
this.value2 = v2;


public int getValue1()
return this.value1;


public int getValue2()
return this.value2;


@Override
public int hashCode()
final int prime = 31;
int result = 1;
result = prime * result + this.value1;
result = prime * result + this.value2;
return result;


@Override
public boolean equals(final Object obj)
if (this == obj)
return true;

if (obj == null)
return false;

if (this.getClass() != obj.getClass())
return false;

final MyObj other = (MyObj) obj;
if (this.value1 != other.value1)
return false;

if (this.value2 != other.value2)
return false;

return true;



@Test
public void test()
final HashSet<MyObj> set1 = new HashSet<>();
final TreeSet<MyObj> set2 = new TreeSet<>((a, b) -> a.getValue1() - b.getValue1());
Assert.assertEquals(0, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.add(new MyObj(0, 0));
set1.add(new MyObj(1, 1));
set1.add(new MyObj(2, 2));
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK
Assert.assertEquals(0, set2.size()); // OK
set2.add(new MyObj(0, 1));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(1, set2.size());
set2.add(new MyObj(1, 2));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // OK Nothing has been removed
Assert.assertEquals(2, set2.size());
set2.add(new MyObj(2, 3));
set1.removeAll(set2);
Assert.assertEquals(3, set1.size()); // Error Everything has been removed
Assert.assertEquals(3, set2.size());





The problem is still there and MyObj implementation is correct. The problem comes from the fact that I am using the objects from two differents aspects. In one set, I want to keep one instance of each objects based on their equality (as in equals method of the object) and in another set, I want a subset of the first set in which for each value1, I want to keep only the firstly inserted element.



Using a TreeSet seemed valid.



Edit 2:



My bad, I missed that part of the TreeSet documentation:




Note that the ordering maintained by a set (whether or not an
explicit comparator is provided) must be consistent with equals if it
is to correctly implement the Set interface. (See Comparable or
Comparator for a precise definition of consistent withequals.) This is
so because the Set interface is defined interms of the equals
operation, but a TreeSet instance performs all element comparisons
using its compareTo (or compare) method, so two elements that are
deemed equal by this method are, from the standpoint of the set, equal.
The behavior of a set is well-defined even if its ordering is
inconsistent with equals; it just fails to obey the general contract of
the Set interface.




If I understand correctly, I can use a TreeSet for my purpose but can't expect it to behave like I want it to.



Thank you all for your help.







java collections set removeall






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 12 '18 at 16:48

























asked Nov 9 '18 at 17:00









ncenerar

1,0671022




1,0671022











  • @FedericoPeraltaSchaffner Thank you for your comment. I updated my question to add some info.
    – ncenerar
    Nov 12 '18 at 16:50










  • can't you make the comparator passed to the treeset consistent with equals? I.e. make it return 0 only if the elements are equal as per the equals method
    – Federico Peralta Schaffner
    Nov 12 '18 at 16:56











  • @FedericoPeraltaSchaffner Unfortunately, no. In fact, the library I am using creates new instances (different from an equals point of view) for objects that are in reality equal (from my point of view).
    – ncenerar
    Nov 12 '18 at 17:32
















  • @FedericoPeraltaSchaffner Thank you for your comment. I updated my question to add some info.
    – ncenerar
    Nov 12 '18 at 16:50










  • can't you make the comparator passed to the treeset consistent with equals? I.e. make it return 0 only if the elements are equal as per the equals method
    – Federico Peralta Schaffner
    Nov 12 '18 at 16:56











  • @FedericoPeraltaSchaffner Unfortunately, no. In fact, the library I am using creates new instances (different from an equals point of view) for objects that are in reality equal (from my point of view).
    – ncenerar
    Nov 12 '18 at 17:32















@FedericoPeraltaSchaffner Thank you for your comment. I updated my question to add some info.
– ncenerar
Nov 12 '18 at 16:50




@FedericoPeraltaSchaffner Thank you for your comment. I updated my question to add some info.
– ncenerar
Nov 12 '18 at 16:50












can't you make the comparator passed to the treeset consistent with equals? I.e. make it return 0 only if the elements are equal as per the equals method
– Federico Peralta Schaffner
Nov 12 '18 at 16:56





can't you make the comparator passed to the treeset consistent with equals? I.e. make it return 0 only if the elements are equal as per the equals method
– Federico Peralta Schaffner
Nov 12 '18 at 16:56













@FedericoPeraltaSchaffner Unfortunately, no. In fact, the library I am using creates new instances (different from an equals point of view) for objects that are in reality equal (from my point of view).
– ncenerar
Nov 12 '18 at 17:32




@FedericoPeraltaSchaffner Unfortunately, no. In fact, the library I am using creates new instances (different from an equals point of view) for objects that are in reality equal (from my point of view).
– ncenerar
Nov 12 '18 at 17:32












3 Answers
3






active

oldest

votes


















2














 AtomicReference a = new AtomicReference<>("A");
AtomicReference a2 = new AtomicReference<>("A");
System.out.println(a==a2);


your answer lies within.



if instead of Object you use a custom class and you Override equals method it will work as expected.



to get this to work



class AtomicString{
private AtomicReference<String> s;

public AtomicString(String s)
this.s = new AtomicReference<>(s);


@Override public boolean equals(Object o)

public AtomicReference<String> getS()
return s;


@Override public int hashCode()
return Objects.hash(s.get());






share|improve this answer






















  • The thing is that I am relying on a final class from a libray and cannot adapt it easily. But I updated my question to add some information. Anyway, thank you for your answer.
    – ncenerar
    Nov 12 '18 at 16:51


















1














The problem really is the inconsistent "equality" logic. Both TreeSet and HashSet inherit AbstractSet#removeAll, which iterates over the smaller set, therefore using that set's object comparison. As it turns out, "equality" logic can be overridden using a TreeSet.



This is a problem that you can avoid by choosing one of the two Set implementations. If you choose TreeSet, then you must also use the same comparator.



You can't really use HashSet in this case because AtomicReference doesn't have an implementation of equals/hashCode that would work for you. So your only practical choice is to use TreeSet:



Comparator<Object> comparator = (a, b) -> a.toString().compareTo(b.toString());
final Set<Object> set1 = new TreeSet<>(comparator);
final Set<Object> set2 = new TreeSet<>(comparator);


This will break your current tests, but because elements are now being removed as they should (according to your comparator's logic).






share|improve this answer




















  • I updated my question to add some information and try to be as precise as possible. You are right but unfortunately, I must mix different kind of sets.
    – ncenerar
    Nov 12 '18 at 16:56


















0














After searching and reading correctly the documentation about TreeSet, it turns out that:




Note that the ordering maintained by a set (whether or not an
explicit comparator is provided) must be consistent with equals if it
is to correctly implement the Set interface. (See Comparableor
Comparator for a precise definition of consistent with equals.) This is
so because the Set interface is defined in terms of the equals
operation, but a TreeSet instance performs all element comparisons
using its compareTo (or compare) method, so two elements that are
deemed equal by this method are, from the standpoint of the set, equal.
The behavior of a set is well-defined even if its ordering is
inconsistent with equals; it just fails to obey the general contract of
the Set interface.




Which means that the TreeSet used in the example cannot be used as a Set. Therefore, the easiest solution is to create a HashSet for the removeAlloperations by replacing every:



set1.removeAll(set2);


by



set1.removeAll(new HashSet<>(set2));


Maybe not the best solution from a performance point of view but a working one.



Thank you all!






share|improve this answer




















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53230222%2fhow-to-guarantee-the-behavior-of-set-removeall-with-different-type-of-sets%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2














     AtomicReference a = new AtomicReference<>("A");
    AtomicReference a2 = new AtomicReference<>("A");
    System.out.println(a==a2);


    your answer lies within.



    if instead of Object you use a custom class and you Override equals method it will work as expected.



    to get this to work



    class AtomicString{
    private AtomicReference<String> s;

    public AtomicString(String s)
    this.s = new AtomicReference<>(s);


    @Override public boolean equals(Object o)

    public AtomicReference<String> getS()
    return s;


    @Override public int hashCode()
    return Objects.hash(s.get());






    share|improve this answer






















    • The thing is that I am relying on a final class from a libray and cannot adapt it easily. But I updated my question to add some information. Anyway, thank you for your answer.
      – ncenerar
      Nov 12 '18 at 16:51















    2














     AtomicReference a = new AtomicReference<>("A");
    AtomicReference a2 = new AtomicReference<>("A");
    System.out.println(a==a2);


    your answer lies within.



    if instead of Object you use a custom class and you Override equals method it will work as expected.



    to get this to work



    class AtomicString{
    private AtomicReference<String> s;

    public AtomicString(String s)
    this.s = new AtomicReference<>(s);


    @Override public boolean equals(Object o)

    public AtomicReference<String> getS()
    return s;


    @Override public int hashCode()
    return Objects.hash(s.get());






    share|improve this answer






















    • The thing is that I am relying on a final class from a libray and cannot adapt it easily. But I updated my question to add some information. Anyway, thank you for your answer.
      – ncenerar
      Nov 12 '18 at 16:51













    2












    2








    2






     AtomicReference a = new AtomicReference<>("A");
    AtomicReference a2 = new AtomicReference<>("A");
    System.out.println(a==a2);


    your answer lies within.



    if instead of Object you use a custom class and you Override equals method it will work as expected.



    to get this to work



    class AtomicString{
    private AtomicReference<String> s;

    public AtomicString(String s)
    this.s = new AtomicReference<>(s);


    @Override public boolean equals(Object o)

    public AtomicReference<String> getS()
    return s;


    @Override public int hashCode()
    return Objects.hash(s.get());






    share|improve this answer














     AtomicReference a = new AtomicReference<>("A");
    AtomicReference a2 = new AtomicReference<>("A");
    System.out.println(a==a2);


    your answer lies within.



    if instead of Object you use a custom class and you Override equals method it will work as expected.



    to get this to work



    class AtomicString{
    private AtomicReference<String> s;

    public AtomicString(String s)
    this.s = new AtomicReference<>(s);


    @Override public boolean equals(Object o)

    public AtomicReference<String> getS()
    return s;


    @Override public int hashCode()
    return Objects.hash(s.get());







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 9 '18 at 21:48

























    answered Nov 9 '18 at 17:13









    mavriksc

    55548




    55548











    • The thing is that I am relying on a final class from a libray and cannot adapt it easily. But I updated my question to add some information. Anyway, thank you for your answer.
      – ncenerar
      Nov 12 '18 at 16:51
















    • The thing is that I am relying on a final class from a libray and cannot adapt it easily. But I updated my question to add some information. Anyway, thank you for your answer.
      – ncenerar
      Nov 12 '18 at 16:51















    The thing is that I am relying on a final class from a libray and cannot adapt it easily. But I updated my question to add some information. Anyway, thank you for your answer.
    – ncenerar
    Nov 12 '18 at 16:51




    The thing is that I am relying on a final class from a libray and cannot adapt it easily. But I updated my question to add some information. Anyway, thank you for your answer.
    – ncenerar
    Nov 12 '18 at 16:51













    1














    The problem really is the inconsistent "equality" logic. Both TreeSet and HashSet inherit AbstractSet#removeAll, which iterates over the smaller set, therefore using that set's object comparison. As it turns out, "equality" logic can be overridden using a TreeSet.



    This is a problem that you can avoid by choosing one of the two Set implementations. If you choose TreeSet, then you must also use the same comparator.



    You can't really use HashSet in this case because AtomicReference doesn't have an implementation of equals/hashCode that would work for you. So your only practical choice is to use TreeSet:



    Comparator<Object> comparator = (a, b) -> a.toString().compareTo(b.toString());
    final Set<Object> set1 = new TreeSet<>(comparator);
    final Set<Object> set2 = new TreeSet<>(comparator);


    This will break your current tests, but because elements are now being removed as they should (according to your comparator's logic).






    share|improve this answer




















    • I updated my question to add some information and try to be as precise as possible. You are right but unfortunately, I must mix different kind of sets.
      – ncenerar
      Nov 12 '18 at 16:56















    1














    The problem really is the inconsistent "equality" logic. Both TreeSet and HashSet inherit AbstractSet#removeAll, which iterates over the smaller set, therefore using that set's object comparison. As it turns out, "equality" logic can be overridden using a TreeSet.



    This is a problem that you can avoid by choosing one of the two Set implementations. If you choose TreeSet, then you must also use the same comparator.



    You can't really use HashSet in this case because AtomicReference doesn't have an implementation of equals/hashCode that would work for you. So your only practical choice is to use TreeSet:



    Comparator<Object> comparator = (a, b) -> a.toString().compareTo(b.toString());
    final Set<Object> set1 = new TreeSet<>(comparator);
    final Set<Object> set2 = new TreeSet<>(comparator);


    This will break your current tests, but because elements are now being removed as they should (according to your comparator's logic).






    share|improve this answer




















    • I updated my question to add some information and try to be as precise as possible. You are right but unfortunately, I must mix different kind of sets.
      – ncenerar
      Nov 12 '18 at 16:56













    1












    1








    1






    The problem really is the inconsistent "equality" logic. Both TreeSet and HashSet inherit AbstractSet#removeAll, which iterates over the smaller set, therefore using that set's object comparison. As it turns out, "equality" logic can be overridden using a TreeSet.



    This is a problem that you can avoid by choosing one of the two Set implementations. If you choose TreeSet, then you must also use the same comparator.



    You can't really use HashSet in this case because AtomicReference doesn't have an implementation of equals/hashCode that would work for you. So your only practical choice is to use TreeSet:



    Comparator<Object> comparator = (a, b) -> a.toString().compareTo(b.toString());
    final Set<Object> set1 = new TreeSet<>(comparator);
    final Set<Object> set2 = new TreeSet<>(comparator);


    This will break your current tests, but because elements are now being removed as they should (according to your comparator's logic).






    share|improve this answer












    The problem really is the inconsistent "equality" logic. Both TreeSet and HashSet inherit AbstractSet#removeAll, which iterates over the smaller set, therefore using that set's object comparison. As it turns out, "equality" logic can be overridden using a TreeSet.



    This is a problem that you can avoid by choosing one of the two Set implementations. If you choose TreeSet, then you must also use the same comparator.



    You can't really use HashSet in this case because AtomicReference doesn't have an implementation of equals/hashCode that would work for you. So your only practical choice is to use TreeSet:



    Comparator<Object> comparator = (a, b) -> a.toString().compareTo(b.toString());
    final Set<Object> set1 = new TreeSet<>(comparator);
    final Set<Object> set2 = new TreeSet<>(comparator);


    This will break your current tests, but because elements are now being removed as they should (according to your comparator's logic).







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 9 '18 at 17:33









    ernest_k

    20k42043




    20k42043











    • I updated my question to add some information and try to be as precise as possible. You are right but unfortunately, I must mix different kind of sets.
      – ncenerar
      Nov 12 '18 at 16:56
















    • I updated my question to add some information and try to be as precise as possible. You are right but unfortunately, I must mix different kind of sets.
      – ncenerar
      Nov 12 '18 at 16:56















    I updated my question to add some information and try to be as precise as possible. You are right but unfortunately, I must mix different kind of sets.
    – ncenerar
    Nov 12 '18 at 16:56




    I updated my question to add some information and try to be as precise as possible. You are right but unfortunately, I must mix different kind of sets.
    – ncenerar
    Nov 12 '18 at 16:56











    0














    After searching and reading correctly the documentation about TreeSet, it turns out that:




    Note that the ordering maintained by a set (whether or not an
    explicit comparator is provided) must be consistent with equals if it
    is to correctly implement the Set interface. (See Comparableor
    Comparator for a precise definition of consistent with equals.) This is
    so because the Set interface is defined in terms of the equals
    operation, but a TreeSet instance performs all element comparisons
    using its compareTo (or compare) method, so two elements that are
    deemed equal by this method are, from the standpoint of the set, equal.
    The behavior of a set is well-defined even if its ordering is
    inconsistent with equals; it just fails to obey the general contract of
    the Set interface.




    Which means that the TreeSet used in the example cannot be used as a Set. Therefore, the easiest solution is to create a HashSet for the removeAlloperations by replacing every:



    set1.removeAll(set2);


    by



    set1.removeAll(new HashSet<>(set2));


    Maybe not the best solution from a performance point of view but a working one.



    Thank you all!






    share|improve this answer

























      0














      After searching and reading correctly the documentation about TreeSet, it turns out that:




      Note that the ordering maintained by a set (whether or not an
      explicit comparator is provided) must be consistent with equals if it
      is to correctly implement the Set interface. (See Comparableor
      Comparator for a precise definition of consistent with equals.) This is
      so because the Set interface is defined in terms of the equals
      operation, but a TreeSet instance performs all element comparisons
      using its compareTo (or compare) method, so two elements that are
      deemed equal by this method are, from the standpoint of the set, equal.
      The behavior of a set is well-defined even if its ordering is
      inconsistent with equals; it just fails to obey the general contract of
      the Set interface.




      Which means that the TreeSet used in the example cannot be used as a Set. Therefore, the easiest solution is to create a HashSet for the removeAlloperations by replacing every:



      set1.removeAll(set2);


      by



      set1.removeAll(new HashSet<>(set2));


      Maybe not the best solution from a performance point of view but a working one.



      Thank you all!






      share|improve this answer























        0












        0








        0






        After searching and reading correctly the documentation about TreeSet, it turns out that:




        Note that the ordering maintained by a set (whether or not an
        explicit comparator is provided) must be consistent with equals if it
        is to correctly implement the Set interface. (See Comparableor
        Comparator for a precise definition of consistent with equals.) This is
        so because the Set interface is defined in terms of the equals
        operation, but a TreeSet instance performs all element comparisons
        using its compareTo (or compare) method, so two elements that are
        deemed equal by this method are, from the standpoint of the set, equal.
        The behavior of a set is well-defined even if its ordering is
        inconsistent with equals; it just fails to obey the general contract of
        the Set interface.




        Which means that the TreeSet used in the example cannot be used as a Set. Therefore, the easiest solution is to create a HashSet for the removeAlloperations by replacing every:



        set1.removeAll(set2);


        by



        set1.removeAll(new HashSet<>(set2));


        Maybe not the best solution from a performance point of view but a working one.



        Thank you all!






        share|improve this answer












        After searching and reading correctly the documentation about TreeSet, it turns out that:




        Note that the ordering maintained by a set (whether or not an
        explicit comparator is provided) must be consistent with equals if it
        is to correctly implement the Set interface. (See Comparableor
        Comparator for a precise definition of consistent with equals.) This is
        so because the Set interface is defined in terms of the equals
        operation, but a TreeSet instance performs all element comparisons
        using its compareTo (or compare) method, so two elements that are
        deemed equal by this method are, from the standpoint of the set, equal.
        The behavior of a set is well-defined even if its ordering is
        inconsistent with equals; it just fails to obey the general contract of
        the Set interface.




        Which means that the TreeSet used in the example cannot be used as a Set. Therefore, the easiest solution is to create a HashSet for the removeAlloperations by replacing every:



        set1.removeAll(set2);


        by



        set1.removeAll(new HashSet<>(set2));


        Maybe not the best solution from a performance point of view but a working one.



        Thank you all!







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 12 '18 at 17:08









        ncenerar

        1,0671022




        1,0671022



























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53230222%2fhow-to-guarantee-the-behavior-of-set-removeall-with-different-type-of-sets%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            Barbados

            How to read a connectionString WITH PROVIDER in .NET Core?

            Node.js Script on GitHub Pages or Amazon S3