Иногда вы хотите отфильтровать Stream
несколько условий:
myList.stream().filter(x -> x.size() > 10).filter(x -> x.isCool()) ...
или вы можете сделать то же самое со сложным условием и одним filter
:
myList.stream().filter(x -> x.size() > 10 && x -> x.isCool()) ...
Я предполагаю, что второй подход имеет лучшие характеристики производительности, но я этого не знаю .
Первый подход выигрывает в удобочитаемости, но что лучше для производительности?
Ответы:
Код, который должен быть выполнен для обеих альтернатив, настолько похож, что вы не можете предсказать результат надежно. Базовая структура объекта может отличаться, но это не является проблемой для оптимизатора точки доступа. Так что это зависит от других окружающих условий, которые приведут к более быстрому выполнению, если есть какая-либо разница.
Объединение двух экземпляров фильтров создает больше объектов и , следовательно , более делегирование код , но это может измениться , если вы используете ссылки метод , а не лямбда - выражений, например , заменить
filter(x -> x.isCool())
наfilter(ItemType::isCool)
. Таким образом, вы исключили синтетический метод делегирования, созданный для вашего лямбда-выражения. Таким образом, объединение двух фильтров с использованием двух ссылок на методы может создать такой же или меньший код делегирования, чем одинfilter
вызов с использованием лямбда-выражения с&&
.Но, как уже говорилось, этот вид издержек будет устранен оптимизатором HotSpot и незначителен.
Теоретически, два фильтра легче распараллелить, чем один фильтр, но это актуально только для довольно сложных вычислительных задач ».
Так что простого ответа нет.
Суть в том, что не думайте о таких различиях в производительности ниже порога обнаружения запаха. Используйте то, что более читабельно.
And… и потребуется реализация, выполняющая параллельную обработку последующих этапов, путь, который в настоящее время не принят стандартной реализацией Stream
источник
Сложное условие фильтрации лучше с точки зрения производительности, но наилучшая производительность покажет старомодную петлю со стандартом
if clause
- лучший вариант. Разница в малом массиве 10 элементов может составлять ~ 2 раза, для большого массива разница не так велика.Вы можете взглянуть на мой проект GitHub , где я проводил тесты производительности для нескольких вариантов итераций массива.
Для операций с пропускной способностью 10 элементов для небольшого массива: для операций с пропускной способностью 10 000 элементов: для операций с пропускной способностью 1 000 000 элементов:
ПРИМЕЧАНИЕ: тесты выполняются на
ОБНОВЛЕНИЕ: Java 11 имеет некоторый прогресс в производительности, но динамика остается прежней
Режим тестирования: пропускная способность, количество операций / время
источник
Этот тест показывает, что ваш второй вариант может работать значительно лучше. Сначала выводы, затем код:
теперь код:
источник
Test #1: {count=100, sum=7207, min=65, average=72.070000, max=91} Test #3: {count=100, sum=7959, min=72, average=79.590000, max=97} Test #2: {count=100, sum=8869, min=79, average=88.690000, max=110}
Это результат 6 различных комбинаций примера теста, совместно используемых @Hank D. Очевидно, что предикат формы
u -> exp1 && exp2
очень эффективен во всех случаях.источник