Is it possible that TreeSet equals HashSet but not HashSet equals TreeSet

Your interviewer is right, they do not hold equivalence relation for some specific cases. It is possible that TreeSet can be equal to HashSet and not vice-versa. Here is an example:

TreeSet<String> treeSet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
HashSet<String> hashSet = new HashSet<>();
treeSet.addAll(List.of("A", "b"));
hashSet.addAll(List.of("A", "B"));
System.out.println(hashSet.equals(treeSet)); // false
System.out.println(treeSet.equals(hashSet)); // true

The reason for this is that a TreeSet uses comparator to determine if an element is duplicate while HashSet uses equals.

Quoting TreeSet:

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.


It’s not possible without violating the contract of either equals or Set. The definition of equals in Java requires symmetry, I.e. a.equals(b) must be the same as b.equals(a).

In fact, the very documentation of Set 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). This definition ensures that the equals method works properly across different implementations of the set interface.


NO, this is impossible without violating general contract of the equals method of the Object class, which requires symmetry, i. e. x.equals(y) if and only if y.equals(x).

BUT, classes TreeSet and HashSet implement the equals contract of the Set interface differently. This contract requires, among other things, that every member of the specified set is contained in this set. To determine whether an element is in the set the contains method is called, which for TreeSet uses Comparator and for HashSet uses hashCode.

And finally:

YES, this is possible in some cases.


This is a quote from the book Java Generics and Collections:

In principle, all that a client should need to know is how to keep to its side of the contract; if it fails to do that, all bets are off and there should be no need to say exactly what the supplier will do.

So the answer is : Yes it can happen but only when you don't keep to your side of the contract with Java. Here you can say Java has violated the symmetric property of equality but if that happen be sure that you are the one who has broken the contract of some other interfaces first. Java has already documented this behaviour.

Generally you should read documentation of Comparator and Comparable interfaces to use them correctly in sorted collections.

This question is somehow answered in Effective Java Third Edition Item 14 on pages 66-68.

This is a quote from the book when defining contract for implementing Comparable interface(note that this is only part of the whole contract):

• It is strongly recommended, but not required, that (x.compareTo(y) == 0) == (x.equals(y)). Generally speaking, any class that implements the Comparable interface and violates this condition should clearly indicate this fact. The recommended language is “Note: This class has a natural ordering that is inconsistent with equals.”

It says It is strongly recommended, but not required, it means you are allowed to have classes for which x.compareTo(y)==0 does not mean x.equal(y)==true.(But if it is implemented that way you can't use them as an element in sorted collections, this is exactly the case with BigDecimal)

The paragraph of the book describing this part of the contract of Comparable interface is worth mentioning:

It is a strong suggestion rather than a true requirement, simply states that the equality test imposed by the compareTo method should generally return the same results as the equals method. If this provision is obeyed, the ordering imposed by the compareTo method is said to be consistent with equals. If it’s violated, the ordering is said to be inconsistent with equals. A class whose compareTo method imposes an order that is inconsistent with equals will still work, but sorted collections containing elements of the class may not obey the general contract of the appropriate collec- tion interfaces (Collection, Set, or Map). This is because the general contracts for these interfaces are defined in terms of the equals method, but sorted collec- tions use the equality test imposed by compareTo in place of equals. It is not a catastrophe if this happens, but it’s something to be aware of.

Actually we have some classes in Java itself that did not follow this recommendation. BigDecimal is one of them and this is mentioned in the book.

For example, consider the BigDecimal class, whose compareTo method is inconsistent with equals. If you create an empty HashSet instance and then add new BigDecimal("1.0") and new BigDecimal("1.00"), the set will contain two elements because the two BigDecimal instances added to the set are unequal when compared using the equals method. If, however, you perform the same procedure using a TreeSet instead of a HashSet, the set will contain only one element because the two BigDecimal instances are equal when compared using the compareTo method. (See the BigDecimal documentation for details.)

However this behaviour is documented in BigDecimal Documentation. Let's have a look at that part of the documentation:

Note: care should be exercised if BigDecimal objects are used as keys in a SortedMap or elements in a SortedSet since BigDecimal's natural ordering is inconsistent with equals. See Comparable, SortedMap or SortedSet for more information.

So although you can write code like below you should not do it because the BigDecimal class has prohibited this usage:

Set<BigDecimal> treeSet = new TreeSet<>();
Set<BigDecimal> hashSet = new HashSet<>();
treeSet.add(new BigDecimal("1.00"));
treeSet.add(new BigDecimal("2.0"));
hashSet.add(new BigDecimal("1.00"));
hashSet.add(new BigDecimal("2.00"));
System.out.println(hashSet.equals(treeSet)); // false
System.out.println(treeSet.equals(hashSet)); // true

Note that Comparable will be used as natural ordering of the elements when you don't pass any comparator to TreeSet or TreeMap, the same thing can happen when you pass Comparator to those class constructor. This is mentioned in the Comparator documentation:

The ordering imposed by a comparator c on a set of elements S is said to be consistent with equals if and only if c.compare(e1, e2)==0 has the same boolean value as e1.equals(e2) for every e1 and e2 in S.

Caution should be exercised when using a comparator capable of imposing an ordering inconsistent with equals to order a sorted set (or sorted map). Suppose a sorted set (or sorted map) with an explicit comparator c is used with elements (or keys) drawn from a set S. If the ordering imposed by c on S is inconsistent with equals, the sorted set (or sorted map) will behave "strangely." In particular the sorted set (or sorted map) will violate the general contract for set (or map), which is defined in terms of equals.

So considering this documention of Comparator, following example given by @Aniket Sahrawat is not supported to work:

TreeSet<String> treeSet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
HashSet<String> hashSet = new HashSet<>();
treeSet.addAll(List.of("A", "b"));
hashSet.addAll(List.of("A", "B"));
System.out.println(hashSet.equals(treeSet)); // false
System.out.println(treeSet.equals(hashSet)); // true

In a nutshell the answer is: Yes it can happen but only when you break the documented contract of one of the aforementioned interfaces(SortedSet, Comparable, Comparator).


There already are good answers, but I would like to approach this from a bit more general perspective.

In the Mathematics, Logic, and correspondingly, in the Computer Science, "is equal to" is a Symmetric Binary Relation, which means, that if A is equal to B then B is equal to A.

So, if TreeSet X equals HashSet Y, then HashSet Y must equal to TreeSet X, and that must be true always.

If, however, symmetric property of the Equality is violated (i.e. Equality is not implemented correctly), then x.equals(y) might not mean y.equals(x).


The documentation of Object#equals method in Java, explicitly states, that:

The equals method implements an equivalence relation on non-null object references.

hence, it implements the symmetric property, and if it does not, then it violates the Equality, in general, and violates the Object#equals method, specifically in Java.