Ответ 1
Вы можете фильтровать поток на "Civic" or "Focus"
, а затем запустить коллекционер на getModel()
, возвращая Set<String>
. Затем вы можете проверить, содержит ли ваш набор оба ключа.
Set<String> models = reportElements.stream()
.map(Car::getModel)
.filter(model -> model.equals("Focus") || model.equals("Civic"))
.collect(Collectors.toSet());
return models.contains("Focus") && models.contains("Civic");
Однако это обработает весь поток; он не будет "быстро преуспеть", если оба обнаружены.
Ниже приведен метод короткого замыкания с быстрым успехом. (Обновлено для включения комментариев и пояснений из комментариев ниже)
return reportElements.stream()
.map(Car::getModel)
.filter(model -> model.equals("Focus") || model.equals("Civic"))
.distinct()
.limit(2)
.count() == 2;
Ломать потоковые операции по одному за раз, мы имеем:
.map(Car::getModel)
Эта операция превращает поток автомобилей в поток моделей автомобилей.
Мы делаем это для повышения эффективности.
Вместо того чтобы называть car.getModel()
несколько раз в разных местах в оставшейся части конвейера (дважды в filter(...)
для проверки по каждой из желаемых моделей и снова для операции distinct()
), мы применяем эту операцию отображения один раз.
Обратите внимание, что это не создает "временную карту", упомянутую в комментариях;
он просто переводит автомобиль в модель автомобиля для следующего этапа трубопровода.
.filter(model -> model.equals("Focus") || model.equals("Civic"))
Это фильтрует поток моделей автомобилей, позволяя пропускать только модели "Focus" и "Civic".
.distinct()
Эта операция конвейера - это промежуточная операция с состоянием.
Он запоминает каждую модель автомобиля, которую он видит во временном Set
.
(Вероятно, это временная карта, упомянутая в комментариях.)
Только если модель не существует во временном наборе,
будет ли он (a) добавлен в набор и (b) передан на следующий этап конвейера.
В этот момент в конвейере в потоке может быть не более двух элементов: "Фокус" или "Гражданский", либо ни один, ни тот и другой.
Мы знаем это, потому что знаем, что filter(...)
будет только передавать эти две модели, и мы знаем, что distinct()
удалит любые дубликаты.
Однако этот конвейер потока сам не знает этого.
Он будет продолжать передавать автомобильные объекты на этап map
, который должен быть преобразован в строки модели, передать эти модели на этап filter
и отправить на любой подходящий элемент на этап distinct
.
Он не может сказать, что это бесполезно, потому что он не понимает, что через алгоритм не может пройти ничего другого; он просто выполняет инструкции.
Но мы понимаем.
Не более двух отдельных моделей могут проходить через стадию distinct()
.
Итак, мы следуем этому:
.limit(2)
Это короткая замыкающая промежуточная операция состояния. Он поддерживает подсчет количества предметов, которые проходят, и после указанного количества он прекращает поток, заставляя все последующие элементы отбрасываться, даже не начиная по трубопроводу.
В этот момент в конвейере в потоке может быть не более двух элементов: "Фокус" или "Гражданский", либо ни один, ни тот и другой. Но если оба, то поток был усечен и находится в конце.
.count() == 2;
Подсчитайте количество элементов, которые прошли через конвейер, и протестируйте его с нужным номером.
Если мы найдем обе модели, поток немедленно прекратится, count()
вернет 2, и будет возвращен true
.
Если обе модели не присутствуют, конечно, поток обрабатывается до конца, count()
будет возвращать значение меньше двух, и будет false
.
Пример, используя бесконечный поток моделей. Каждая третья модель является "Civic", каждая 7-я модель является "Focus", остальные - "Model #":
boolean matched = IntStream.iterate(1, i -> i + 1)
.mapToObj(i -> i % 3 == 0 ? "Civic" : i % 7 == 0 ? "Focus" : "Model "+i)
.peek(System.out::println)
.filter(model -> model.equals("Civic") || model.equals("Focus"))
.peek(model -> System.out.println(" After filter: " + model))
.distinct()
.peek(model -> System.out.println(" After distinct: " + model))
.limit(2)
.peek(model -> System.out.println(" After limit: " + model))
.count() == 2;
System.out.println("Matched = "+matched);
Вывод:
Model 1
Model 2
Civic
After filter: Civic
After distinct: Civic
After limit: Civic
Model 4
Model 5
Civic
After filter: Civic
Focus
After filter: Focus
After distinct: Focus
After limit: Focus
Matched = true
Обратите внимание, что 3 модели прошли через filter()
, но только 2 прошли мимо distinct()
и limit()
.
Что еще более важно, обратите внимание, что true
был возвращен задолго до того, как был достигнут конец бесконечного потока моделей.
Обобщение решения, поскольку OP хочет что-то, что может работать с людьми, кредитными картами или IP-адресами и т.д., а критерии поиска, вероятно, не являются фиксированным набором из двух элементов:
Set<String> models = Set.of("Focus", "Civic");
return reportElements.stream()
.map( Car::getModel )
.filter( models::contains )
.distinct()
.limit( models.size() )
.count() == models.size();
Здесь, при произвольном наборе models
, может быть получено существование любого конкретного набора моделей автомобилей, не ограничиваясь только 2.