When Are Two Java Collections Equal?

The equals method in the Java Collections Framework has a very intuitive meaning: two collections are equal if their elements are equal, taking the order of the elements into account if relevant. But does that mean that a modifiable collection can be equal to an unmodifiable collection? And what about ordered and sorted collections?

Lego Classic Space Minifigs” by Dutch Treat / CC BY 2.0

Let’s start by adding some details to the definition of that equals method in the Java Collections Framework. There are actually two definitions: one for sets, and one for lists. Two sets are equal if they contain the same number of elements, and all the elements in one set are contained in the other (and vice versa). The same applies to lists, but in order for lists to be equal, their elements need to have the same order too.

In most cases, this definition of equality is what you need when comparing two collections. By coincidence (or perhaps not entirely by coincidence, because the Java language is carefully designed), these definitions work out fine when sets and lists are used as fields in Java records. However, there are cases where you need a stricter or looser definition of equality between collections. An example could be when you’re writing a unit test, and you want to compare two collections in the assert section. One of the two collections you want to compare is the actual result from a method call, while the other one is a representation of what you’re expecting.

Stricter Definitions of Equality

In some cases, you’ll want to verify not only that a collection contains the expected content, but also whether it’s modifiable or not. As it happens, testing for modifiability is a very tricky thing in the Java Collections Framework. It’s certainly not available as a property you can check through the API. You could of course run a check against a collection’s runtime class in your unit test, and conclude on the basis of that, but I wouldn’t recommend doing so. Alternatively, you could try to modify the collection as part of your unit test, but even that doesn’t give you a guarantee, only an indication. It’s perfectly possible to implement collections within the Java Collections Framework where modifiability changes throughout a collection’s lifetime. What’s for certain is that it isn’t part of the definition of the equals method, so yes, a modifiable collection can be equal to an unmodifiable collection.

The same applies to sorted sets, even if they have different comparators. This means that if you want to write a unit test on a method producing a SortedSet, and you want to make sure that the result doesn’t only contain the right elements, but also the right comparator, you’ll need to add an explicit assertion for that to your unit test. In fact, if you only depend on the equals method, a SortedSet can just as well be equal to a HashSet or any other class implementing the Set interface.

Even though these two use cases seem problematic for unit testing, in most cases it’s an advantage that the equals method has the definition that it has in the Java Collections Framework. It’s what allows you to write assertions like Assert.assertEquals(Set.of(“foo”, “bar”), actual) without having to care what kind of set the factory method Set.of produces.

A Looser Definition of Equality

But you can also run into the opposite problem. Sometimes you need what some other collections frameworks call a ‘bag’: a set that can handle duplicate elements. In such cases, using a list can be a solution, but only if you can work your way around the order imposed on its elements.

For unit tests, sorting the elements of the list before doing a comparison in an assertion can be a solution. But this can only work if you are able to prepare the list for comparison before the equals method is called. If you’re trying to use a list as a bag for a field in a Java record, then you’re in trouble. There’s no way to remove the order requirement from the list’s equals method, inject sorting before the comparison is done, or configure the Java record to use an alternative equals method for the field’s comparison.

Ordered and Sorted Collections

So what about ordered and sorted collections: can they be equal if they contain the same elements, and the comparator in the sorted collection sorts the elements in the same order as in the ordered collection? The short answer is no, they can’t. Sets can be sorted, but they can by definition never be ordered. Lists, on the other hand, are by definition ordered, not sorted, even though the presence of a sort method may give you a different impression. The sort method reorders the elements using a comparator, but as soon as the method returns, the comparator is forgotten by the list. The list may seem to be sorted, but in reality it’s still ordered.

This means that something like Assert.assertEquals(List.of(“foo”, “bar”), aSortedSet) won’t work. Yes, it may make some sense to use an ordered collection to verify that a sorted set contains the correct elements sorted in the correct order. But using lists and sets from the Java Collections Framework, the result of the comparison will always be false. You should probably rather have one or more unit tests verifying the sorted set contains the correct content and comparator, and a couple of other unit tests verifying the sorting done by the comparator.

For completeness: if you do want to compare ordered and sorted collections, you can of course always implement your own ordered and sorted collection type(s), even as an implementation of the Collection interface in the Java Collections Framework. However, you’ll have to keep both types outside of the List and Set hierarchy. If not, you’ll be breaking the contract for the equals method in either List or Set, or both.

When Are Two Collections Equal… Really?

And this leads us back to the question in the title of this article, but on a fundamental level: when are two Java collections equal? The Java Collections Framework’s answer works in most contexts, but not all. So the only correct answer is: it depends, like it usually is in software engineering. Remember that collections, sets and lists are very generic concepts, so expecting an answer that would work one hundred percent of the time, regardless of any context, wouldn’t be fair either.


When Are Two Java Collections Equal? was originally published in Compendium on Medium, where people are continuing the conversation by highlighting and responding to this story.