2

The trick is that this object MediaContainerModel inherits equals(Object) directly from Object and I can't and don't want to override equals in its class definition. This is what I have at the moment:

private void addMediaContainer(MediaContainerModel newMediaContainer, ProductModel product) {
    List<MediaContainerModel> galleryImages = new ArrayList<>(product.getGalleryImages());
    MediaContainerModel inserted = null;

    // if a MediaContainer with same qualifier as newMediaContainer already exists, replace it 
    // with the new one to prevent duplicates
    for (int i = 0; i < galleryImages.size(); i++) {
        if (galleryImages.get(i).getQualifier().equals(newMediaContainer.getQualifier())) {
            inserted = galleryImages.set(i, newMediaContainer);
        }
    }
    // if not, add it
    if (inserted == null) {
        galleryImages.add(newMediaContainer);
        galleryImages.sort((image1, image2) -> image2.getQualifier().compareTo(image1.getQualifier()));
    }
    product.setGalleryImages(galleryImages);
}

I want to do the same thing without the ugly for-loop by overriding MediaContainerModel.equals(Object) for this method only so I can use List.indexOf(Object) or something with lambdas. Is this possible in Java? If so how? Thanks!

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183

1 Answers1

1

without using a loop

I bet you are looking for the way:

List<MediaContainerModel> galleryImages = new ArrayList<>(product.getGalleryImages());

galleryImages.stream()
    .filter(image -> newMediaContainer.getQualifier()                 // filter the equal ones
                                      .equals(image.getQualifier()))
    .findAny()                                                        // find any existing
    .ifPresent(image -> {                                             // add if present
        galleryImages.add(newMediaContainer);
        galleryImages.sort(Comparator.comparing(MediaContainerModel::getQualifier));
    });

product.setGalleryImages(galleryImages);

Few notes:

  • The filtering uses exhaustive iteration as well as for-loop which means that all elements are iterated and multiple equal MediaContainerModel objects with same qualifiers. That's fine as long as you want to find if there is any qualified (findAny). Otherwise, to find the last one, you have to replace the line with:

    .reduce((first, second) -> second)
    
  • The result using Java Stream API is a bit clumsy. I see you insert a new element and sort the list which means your intention is to keep the list always sorted. If there are no duplicate values allowed, I recommend using rather TreeSet which keeps the elements sorted upon addition or deletion. The whole solution would be the way easier:

    Set<MediaContainerModel> galleryImages = new TreeSet<>(Comparator.comparing(MediaContainerModel::getQualifier));
    galleryImages.addAll(product.getGalleryImages());
    galleryImages.add(newMediaContainer);                      // won't be added if is already present
    product.setGalleryImages(new ArrayList<>(galleryImages));
    

    ... if the ProductModel uses Collection or Set over List, then the last line is more straightforward:

    product.setGalleryImages(galleryImages);
    
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • If I use a `TreeSet`, I would want to update it if it contains a `MediaContainerModel` with the same `qualifier` as `newMediaContainerModel`. Would that be ```galleryImages.remove(newMediaContainer); galleryImages.add(newMediaContainer);``` ? I check for duplicates by comparing `qualifier` but other fields might be different. – Murat Goksel May 11 '20 at 14:17
  • 1
    Yes, correct - you need to remove and add the item since `TreeSet::add` doesn't replace the value if present. Check this relevant question https://stackoverflow.com/questions/2579679/maintaining-treeset-sort-as-object-changes-value – Nikolas Charalambidis May 11 '20 at 15:30