Ваш подход работает, потому что потоковый конвейер состоит только из операции без сохранения состояния.В таких сочетаниях последовательная оценка потока может обрабатывать по одному элементу за раз, поэтому доступ к экземплярам оболочки не перекрывается, как показано на рисунке .Но обратите внимание, что это не гарантированное поведение.
Это определенно не работает с такими операциями с состоянием, как sorted
и distinct
.Он также не может работать с операциями сокращения, поскольку они всегда должны содержать как минимум два элемента для обработки, которые включают reduce
, min
и max
.В случае collect
это зависит от конкретного Collector
.forEachOrdered
не будет работать с параллельными потоками из-за необходимой буферизации.
Обратите внимание, что параллельная обработка будет проблематичной, даже если вы используете TheadLocal
для создания оберток, ограниченных потоками, так как нет гарантии, что объектысозданные в одном рабочем потоке, остаются локальными для этого потока.Рабочий поток может передать частичный результат другому потоку, прежде чем подхватить другую, не связанную рабочую нагрузку.
Таким образом, эта общая изменяемая оболочка работает с определенным набором операций без сохранения состояния, таких как map
, filter
, forEach
, findFirst/Any
, all/any/noneMatch
, в последовательном выполнении конкретной реализации.Вы не получаете гибкость API, поскольку вам нужно ограничить себя, не можете передать поток в произвольный код, ожидающий Stream
, и не использовать произвольные Collector
реализации.У вас также нет инкапсуляции интерфейса, так как вы предполагаете конкретное поведение реализации.
Другими словами, если вы хотите использовать такую изменяемую оболочку, вам лучше использовать цикл, реализующий конкретныйоперация.У вас уже есть недостатки такой ручной реализации, так почему бы не реализовать ее, чтобы иметь преимущества.
Другой аспект, который следует учитывать, - это то, что вы получаете от повторного использования такой изменяемой оболочки.Он работает только в циклах, когда временный объект может быть оптимизирован после применения Escape-анализа в любом случае.В таких сценариях повторное использование объектов, продление срока их службы может фактически ухудшить производительность.
Конечно, масштабирование объектов не является гарантированным поведением.Могут быть сценарии, такие как длинный поток, превышающий предел встраивания JVM, когда объекты не удаляются.Но все же временные объекты не обязательно дороги.
Это было объяснено в этом ответе .Временные объекты выделяются дешево.Основные затраты на сборку мусора связаны с объектами, которые еще живы.Они должны быть пройдены, и их необходимо перемещать, освобождая место для новых распределений.Негативное влияние временных объектов заключается в том, что они могут сократить время между циклами сбора мусора.Но это зависит от скорости выделения и доступного пространства выделения, так что это действительно проблема, которую можно решить, добавив больше оперативной памяти.Больше ОЗУ означает больше времени между циклами GC и больше мертвых объектов, когда происходит GC, что делает чистые затраты GC меньшими.
Тем не менее, недопустимо чрезмерное распределение временных объектов,Существование IntStream
, LongStream
и DoubleStream
показывает это.Но они особенные, так как использование примитивных типов является жизнеспособной альтернативой использованию объектов-оболочек без недостатков повторного использования изменяемой оболочки.Это также отличается тем, что применяется к задачам, в которых тип примитива и тип оболочки семантически эквивалентны.Напротив, вы хотите решить проблему, когда для операции требуется тип оболочки.К примитивному потоку также относится, когда вам нужны объекты для вашей задачи, нет способа обойти бокс, который будет создавать отдельные объекты для разных значений, не разделяя изменяемый объект.
Так что если вы симСуществует проблема, когда существует семантически эквивалентная альтернатива, позволяющая избежать обертки-объекта без существенных проблем, например, просто используя Comparator.comparingInt
вместо Comparator.comparing
, где это возможно, вы все равно можете предпочесть его.Но только тогда.
Короче говоря, в большинстве случаев экономия от повторного использования такого объекта, если таковая имеется, не будет оправдывать недостатки.В особых случаях, когда это выгодно и важно, вам может быть лучше использовать цикл или любую другую конструкцию под вашим полным контролем, вместо использования Stream
.