I need to merge all elements of a listB into another list listA.
If an element is already present (based on a custom equality-check) in listA I don't want to add it.
I don't want to use Set, and I don't want to override equals() and hashCode().
Reasons are, I don't want to prevent duplicates in listA per se, I only want to not merge from listB if there are already elements in listA which I consider being equal.
I don't want to override equals() and hashCode() since that would mean I need to make sure, my implementation of equals() for the elements hold in every circumstance. It might however be, that elements from listB are not fully initialized, i.e. they might miss an object id, where that might be present in elements of listA.
My current approach involves an interface and a Utility-Function:
public interface HasEqualityFunction<T> {
public boolean hasEqualData(T other);
}
public class AppleVariety implements HasEqualityFunction<AppleVariety> {
private String manufacturerName;
private String varietyName;
@Override
public boolean hasEqualData(AppleVariety other) {
return (this.manufacturerName.equals(other.getManufacturerName())
&& this.varietyName.equals(other.getVarietyName()));
}
// ... getter-Methods here
}
public class CollectionUtils {
public static <T extends HasEqualityFunction> void merge(
List<T> listA,
List<T> listB) {
if (listB.isEmpty()) {
return;
}
Predicate<T> exists
= (T x) -> {
return listA.stream().noneMatch(
x::hasEqualData);
};
listA.addAll(listB.stream()
.filter(exists)
.collect(Collectors.toList())
);
}
}
And then I'd use it like this:
...
List<AppleVariety> appleVarietiesFromOnePlace = ... init here with some elements
List<AppleVariety> appleVarietiesFromAnotherPlace = ... init here with some elements
CollectionUtils.merge(appleVarietiesFromOnePlace, appleVarietiesFromAnotherPlace);
...
to get my new list in listA with all elements merged from B.
Is this a good approach? Is there a better/easier way to accomplish the same?