Java: How to perform operations with different definitions of peers?

Java: How to perform operations with different definitions equal?

I have two lists of common POJOs. I need to perform some given operations in lists based on different ways of comparing POJOs in lists.

For example, if my POJO had the following structure:

public class GenericPojo { private String id; private String address; private String city; private String country; private String extraDetails; } 

(with corresponding getters and setters)

Given List1<GenericPojo> and List2<GenericPojo> , how would I find:

List1 - List2 (where the GenericPojo classes are equal, if only the identifiers are equal)

Intersection of List1 and List2 (where id , address , city , country , but not extraDetails of GenericPojo are equal)

Would it be useful to use two different comparator classes? Are there libraries that handle these operations efficiently, or should I try to implement my own?

+7
java list comparator
source share
7 answers

If you must manipulate the class out of your control, I would suggest using delegation. Here is my attempt:

  • Create a RichList<T> wrapper around List that implements the List contract, based on the decorator pattern .
  • Create an inteface EqualityChecker<T> with a single method: public boolean equal (T t1, T, t2).
  • Run this interface twice for your generic pojo: one validates only the identifier, and the other validates the other fields.
  • Add both methods that interest you (specify the substitution and set the intersection), but with an additional argument, which is a specific instance of EqualityChecker<T> , which will perform an equality test for you.

Thus, you can add both operations to all existing List for any object for which you wrote EqualityChecker .

Further improvements: You can also write the default EqualityChecker<T> , which simply calls the equals method on the compared objects. You can then overload both new default EqualityChecker operations.

+2
source share

If your lists do not have duplicates (with repetition to hypothetical custom comparator classes), you can instead use two sets of TreeSets created using your two comparators.

The disadvantage of this (except for limiting duplication) is that the order you get when navigating through the elements depends on the comparators.

+1
source share

Given your specific equality requirements, List#removeAll() and List#retainAll() will not meet your needs, so I think you will need a special implementation to do something similar to both operations.

+1
source share

There is no solution that obeys the List contract, and none of the existing list implementations allow you to supply a comparator. The List contract defines the behavior of the list in terms of the method of each equals(Object) element.

The suggestion of using TreeSets with different comparators is also a breach of contract if the compare comparator method is incompatible with each equals(Object) method.

In practice, you may need to implement your own list classes. You can make it an implementation of a list that does not strictly comply with the "List" contract, but you need to be careful that this does not violate other methods / classes of the library.

0
source share

If you do not want to program the installed operations yourself, and you do not mind spending resources on the processor and memory, you can:

  • build WrappedPojo based on GenericPojo s
  • provide WrappedPojo suitable equals() implementations
  • create new lists of the corresponding WrappedPojo type to perform the operation on
  • copy the contents of GenericPojo back to the original containers (if necessary) after the operation is completed.

Ugly but simple.

0
source share

You can save all this in domain objects using the following approach:

  • Add equals( ... ) to GenericPojo only on id .
  • Define WrappedPojo as a wrapper around GenericPojo using equals( ... ) based on additional GenericPojo fields.
  • For the second use case, use a list of wrapped instances.

I suggest that the root problem try to create one domain class with different equality definitions.

0
source share

Both of the operations you are trying to perform are functional, although Java does not support them very well, and you are likely to write them in a completely different way. You may need to rethink what you are trying to achieve to fit java.

What you do is perform an operation on a projection of a data type (i.e. for a subset of fields)

The operations you use are also Set operations, not List operations. for example, you cannot cross two lists (or at least you must determine what this means). Delete may not perform exactly as you expect from a list.

Imagine you have a method that returns a pojos collection with only the fields you specify. I wrote a library to do this efficiently with a dynamically generated class in the past, to look at functional Java or similar.

 public static <Pojo, Pojo2> Set<Pojo2> project(Collection<Pojo> collection, String... fieldsToRetain); 

List1 - List2 (where the GenericPojo classes are equal, if only the identifiers are equal)

 Set<PojoWithId> setOfIds = project(list1, "id") setOfIds.retainAll(project(list2, "id")); 

Intersection of List1 and List2 (where id, address, city, country, but not extraDetails of GenericPojo are equal)

 Set<PojoWithThreeFields> intersection = project(list1, "id", "address", "city", "country"); intersection.retainAll(project(list2, "id", "address", "city", "country")); 
0
source share

All Articles