Java 8 — Составные объекты с потоковой ссылкой

#java #lambda #java-8 #java-stream

#java #лямбда #java-8 #java-поток

Вопрос:

У меня есть List<Entry> entries , с приведенной ниже структурой кода,

 class Entry {
    public Product getProduct() {
        return product;
    }
}

class Product {

    public List<CategoriesData> getCategories() {
        return categoriesData;
    }
}

class CategoriesData {

    public String getName() {
        return name;
    }
}
  

Я рассматриваю сортировку по Product — CategoriesData — name (из первого элемента в List<CategoriesData> )

 // Not sure how to refer Name within CategoriesData, 
// entries.stream().sorted(
//   Comparator.comparing(Entry::getProduct::getCategories::getName))
//                      .collect(Collectors.toList())
  

Комментарии:

1. Хорошо, не уверен, что это будет за сравнение, но вы можете добиться этого с помощью Comparator.comparing(a -> a.getProduct().getCategories().get(0).getName()) .

2. .get(0) ты уверен?? Это не очень хорошая практика: p

3. @Naman Я получаю ошибку «Метод getProduct () не определен для типа Object», в чем может быть причина?

4. @SyAu надеюсь, у вас есть поток записей, как в вопросе, и тогда на самом деле это не должно заканчиваться упомянутой ошибкой.

Ответ №1:

Используя решение Mureinik, вы можете сделать:

 Comparator<Entry> entryComperator = Comparator
                .comparing(e -> e.getProduct().getCategories().get(0).getName());
        List<Entry> sorted =
                entries.stream()
                        .sorted(entryComperator)
                        .collect(Collectors.toList());
  

Вы могли бы рассмотреть возможность доступа к имени из списка, если список пуст. вы можете скрыть всю эту логику в компараторе, как я сделал выше

Ответ №2:

Если вы пытаетесь выполнить сортировку по первой категории, вам нужно обратиться к ней в компараторе:

 List<Entry> sorted = 
    entries.stream()
           .sorted(Comparator.comparing(
                                  e -> e.getProduct().getCategories().get(0).getName())
           .collect(Collectors.toList())
  

Редактировать:
Чтобы ответить на вопрос в комментариях, для вторичной сортировки вам нужно будет указать тип в Comparator :

 List<Entry> sorted = 
    entries.stream()
           .sorted(Comparator.comparing(
                                  e -> e.getProduct().getCategories().get(0).getName())
                             .thenComparing(
                                  (Entry e) -> e.getProduct().getName())
           .collect(Collectors.toList())
  

Комментарии:

1. Спасибо. Я получаю сообщение об ошибке с сообщением о том, что «Метод getProduct() не определен для объекта типа» . В ‘Entry’ получен метод ‘getProduct’, но он выдает ошибку.

2. @SyAu Какой это тип entries ?

3. ‘entries’ — это массив, содержащий список объектов ‘Entry’

4. @SyAu Make вы собираете результат в List<Entry> так же, как и в ответе. Учитывая, что в вопросе это неизвестно.

5. @Mureinik Я протестировал сортировку по названию категории, и это сработало. Теперь я хотел добавить еще одно поле сортировки, Comparator.comparing(e -> e.getProduct().GetCategories().stream().findFirst().get().getName()) .thenComparing(e -> e.getProduct().getName())) , это выдает ошибку.

Ответ №3:

Благодаря вводу от @Mureinik и внесению некоторых изменений, я получил приведенное ниже, и оно работает. Мое требование немного изменилось, мне нужен результат в виде карты. Название категории является ключом на карте, значением будет список ‘Entry’.

  final Map<String, List<Entry>> sortedMap =
        data.getEntries().stream()
        .sorted(Comparator.comparing(e -> ((Entry) e).getProduct().getCategories().stream().findFirst().get().getName())
               .thenComparing(Comparator.comparing(e -> ((Entry) e).getProduct().getName())) )
        .collect(Collectors.groupingBy(e -> e.getProduct().getCategories().stream().findFirst().get().getName(),
                 LinkedHashMap::new, Collectors.toList()));