I'd say these answers miss a trick.
Bloch, in his essential, wonderful, concise Effective Java, says, in item 47, title "Know and use the libraries", "To summarize, don't reinvent the wheel". And he gives several very clear reasons why not.
There are a few answers here which suggest methods from CollectionUtils
in the Apache Commons Collections library but none has spotted the most beautiful, elegant way of answering this question:
Collection<Object> culprits = CollectionUtils.disjunction( list1, list2 );
if( ! culprits.isEmpty() ){
// ... do something with the culprits, i.e. elements which are not common
}
Culprits: i.e. the elements which are not common to both Lists
. Determining which culprits belong to list1
and which to list2
is relatively straightforward using CollectionUtils.intersection( list1, culprits )
and CollectionUtils.intersection( list2, culprits )
.
However it tends to fall apart in cases like { "a", "a", "b" } disjunction
with { "a", "b", "b" } ... except this is not a failing of the software, but inherent to the nature of the subtleties/ambiguities of the desired task.
You can always examine the source code (l. 287) for a task like this, as produced by the Apache engineers. One benefit of using their code is that it will have been thoroughly tried and tested, with many edge cases and gotchas anticipated and dealt with. You can copy and tweak this code to your heart's content if need be.
NB I was at first disappointed that none of the CollectionUtils
methods provides an overloaded version enabling you to impose your own Comparator
(so you can redefine equals
to suit your purposes).
But from collections4 4.0 there is a new class, Equator
which "determines equality between objects of type T". On examination of the source code of collections4 CollectionUtils.java they seem to be using this with some methods, but as far as I can make out this is not applicable to the methods at the top of the file, using the CardinalityHelper
class... which include disjunction
and intersection
.
I surmise that the Apache people haven't got around to this yet because it is non-trivial: you would have to create something like an "AbstractEquatingCollection" class, which instead of using its elements' inherent equals
and hashCode
methods would instead have to use those of Equator
for all the basic methods, such as add
, contains
, etc. NB in fact when you look at the source code, AbstractCollection
does not implement add
, nor do its abstract subclasses such as AbstractSet
... you have to wait till the concrete classes such as HashSet
and ArrayList
before add
is implemented. Quite a headache.
In the mean time watch this space, I suppose. The obvious interim solution would be to wrap all your elements in a bespoke wrapper class which uses equals
and hashCode
to implement the kind of equality you want... then manipulate Collections
of these wrapper objects.