Как исправить код записи с API потока Java 8?

Я изучаю Java 8 и хочу переписать обычный Java-код с помощью java Stream. Но сделать это лучше. Мой код:

public Set<Product> getProductsByFilter(Map<String, List<String>>filterParams) {

    Set<Product> productsByBrand = new HashSet<Product>();
    Set<Product> productsByCategory = new HashSet<Product>();
    Set<String> criterias = filterParams.keySet();
    if (criterias.contains("brand")) {
        for (String brandName : filterParams.get("brand")) {
            for (Product product : listOfProducts) {
                if (brandName.equalsIgnoreCase(product.
                        getManufacturer())) {
                    productsByBrand.add(product);
                }
            }
        }
    }

    if (criterias.contains("category")) {
        for (String category : filterParams.get("category")) {
            productsByCategory.addAll(this.
                    getProductsByCategory(category));
        }
    }
    productsByCategory.retainAll(productsByBrand);
    return productsByCategory;
}

Я не знаю, как исправить код переформатирования в if (criterias.contains ("brand")).

Не могли бы вы добавить API для продукта? Есть ли в нем ссылка на их бренд или категорию / категории? Я предполагаю, что у продукта только одна марка, но у него может быть несколько категорий.

Valentin Ruano 02.06.2018 00:53

Кроме того, похоже, что если какой-либо из двух критериев «бренд» или «категории» не указан, тогда метод должен возвращать пустой набор .... для него более интуитивно понятно предположить, что в случае упущения либо все бренды, либо все категории приемлемы, поэтому в результате получается еще больший набор. Вы можете уточнить?

Valentin Ruano 02.06.2018 01:02

У меня много брендов и много категорий. У каждого продукта есть одна переменная ссылка на бренд (google, dell, ...) и категории (ноутбук, планшет, смартфон, ...). Этот простой пример для изучения Java 8, Spring MVC, ....

Alex 02.06.2018 02:28

спасибо за разъяснения ... как насчет того факта, что ваш код вернет пустую коллекцию продуктов, если какой-либо критерий фильтра отсутствует во входных данных?

Valentin Ruano 02.06.2018 04:33

Ваш код выглядит так странно. Если критерий brandсуществуют и критерий categoryне существует, тогда вернуть empty. Почему игнорируется коллекция productsByBrand? Другой момент: если у вас есть доступ к listOfProducts в цикле фильтров бренда, почему бы не использовать этот список в цикле фильтров category? Вы можете просто зациклить один раз

Mạnh Quyết Nguyễn 02.06.2018 06:58

list Of Products - это тестовый список. Данные будут получены из БД.

Alex 02.06.2018 11:07

Что ты скажешь о метоне

Alex 02.06.2018 11:13

общедоступный список <продукт> getProductsByCategory (строковая категория) {return listOfProducts.stream (). filter (p -> p.getCategory (). equalsIgnoreCase (категория)). collect (Collectors.toList ()); }

Alex 02.06.2018 11:15

Если критерий brandсуществуют и критерий categoryне существует, тогда возврат пуст. Почему игнорируется коллекция productsByBrand?

Mạnh Quyết Nguyễn 02.06.2018 16:45
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
3
9
94
2

Ответы 2

Если код работает, зачем его менять? Тем не менее, вот решение, использующее потоковый API:

public Set<Product> getProductsByFilter(Map<String, List<String>> filterParams) {

    Set<Product> productsByBrand = filterParams.containsKey("brand") ?
                filterParams.get("brand")
                         .stream()
                         .flatMap(brandName -> listOfProducts.stream()
                                            .filter(product -> brandName.equalsIgnoreCase(product.getManufacturer())))
                         .collect(Collectors.toCollection(HashSet::new)) : new HashSet<>();

   Set<Product> productsByCategory =
            filterParams.containsKey("category") ?
                  filterParams.get("category")
                               .stream()
                               .flatMap(category -> this.getProductsByCategory(category).stream())
                               .collect(Collectors.toCollection(HashSet::new)) : new HashSet<>();

        productsByCategory.retainAll(productsByBrand);
        return productsByCategory;
}

или, как предлагает @shmosel, вы можете избежать тернарного оператора с помощью getOrDefault:

Set<Product> productsByBrand = 
       filterParams.getOrDefault("brand", Collections.emptyList())
                   .stream()
                   .flatMap(brandName -> listOfProducts.stream()
                              .filter(product -> brandName.equalsIgnoreCase(product.getManufacturer())))
                   .collect(Collectors.toCollection(HashSet::new));

Set<Product> productsByCategory =
      filterParams.getOrDefault("category", Collections.emptyList())
                  .stream()
                  .flatMap(category -> this.getProductsByCategory(category).stream())
                  .collect(Collectors.toCollection(HashSet::new));

Не следует предполагать, что toSet() возвращает изменяемый набор.

shmosel 02.06.2018 00:38

Возможно, будет проще уменьшить объем тернарного оператора: filterParams.containsKey("brand") ? filterParams.get("brand").stream() : Stream.empty() Или полностью избежать его: filterParams.getOrDefault("brand", Collections.singleton()).stream()

shmosel 02.06.2018 00:43

@shmosel еще раз хороший крик, хотя во втором примере я полагаю, вы имели в виду filterParams.getOrDefault("brand", Collections.emptyList()), а не Collections.singleton().

Ousmane D. 02.06.2018 00:49

Попытка сделать его максимально основанным на лямбда-потоке.

Сначала текущий код вопроса вернет пустой набор, если какой-либо критерий (бренд или категория) не указан. Если это не ошибка, а предполагаемое поведение, тогда имеет смысл проверить, так ли это, и быстро вернуть пустой набор. Итак, код может начинаться так:

final List<String> filterBrands = filterParams.getOrDefault("brand", Collections.emptyList()));
final List<String> filterCategories = filterParams.getOrDefault("categories", Collections.emptyList()));
if (filterCategories.isEmpty() || filterCategories.isEmpty()) {
  return Collections.emptySet();
}

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

На этом этапе вы можете использовать другой подход к ответу, состоящий в создании набора продуктов с двумя критериями, а затем использовать пересечение. Однако, поскольку вы можете получить доступ к бренду, также известному как производство, непосредственно из Продукта, существует альтернатива, которая не требует явного создания экземпляров таких наборов, мы могли бы улучшить производительность в зависимости от соотношения размера прибыли по сравнению с каждым набором критериев. Итак, если результатом будет всего несколько продуктов ... скажем, 5, но каждый критерий или один из критериев может оказаться несколько тысяч, вы можете сэкономить память или перезарядить процессор, выполнив следующие действия:

final Set<String> manufacturers = filterBrands.stream()
        .map(String::toLowerCase)
        .collect(Collectors.toSet());

return filterCategories.stream()
    .flatMap(this::getProductsByCategory)
    .distinct() // optional but might be better performance 
                // if categories share products.
    .filter(product -> manufacturers.contains(product.getManufacturer().toLowerCase()))
    .collect(Collectors.toSet());

Другие вопросы по теме