Есть ли способ получить индекс объекта в списке без использования цикла - PullRequest
1 голос
/ 09 мая 2020

Хитрость в том, что этот объект MediaContainerModel наследует equals(Object) непосредственно от Object, и я не могу и не хочу заменять equals в определении его класса. Вот что у меня есть на данный момент:

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);
}

Я хочу сделать то же самое без уродливого for-l oop, переопределив MediaContainerModel.equals(Object) только для этого метода, чтобы я мог использовать List.indexOf(Object) или что-то с лямбдами. Возможно ли это в Java? Если да, то как? Спасибо!

1 Ответ

1 голос
/ 11 мая 2020

без использования al oop

Готов поспорить, вы ищете способ :

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);

Несколько примечаний:

  • Фильтрация использует исчерпывающую итерацию, а также for-loop, что означает, что все элементы повторяются и несколько одинаковых MediaContainerModel объектов с одинаковыми квалификаторами. Это нормально, если вы хотите узнать, есть ли у вас квалифицированные (findAny). В противном случае, чтобы найти последний, вам нужно заменить строку на:

    .reduce((first, second) -> second)
    
  • Результат с использованием Java Stream API немного неуклюжий. Я вижу, вы вставляете новый элемент и сортируете список, а это означает, что вы намерены всегда сохранять список отсортированным. Если повторяющиеся значения не допускаются, я рекомендую использовать TreeSet, который сохраняет элементы отсортированными при добавлении или удалении. Все решение было бы проще:

    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));
    

    ... если ProductModel использует Collection или Set вместо List, то последняя строка будет более простой:

    product.setGalleryImages(galleryImages);
    
...