Побочные эффекты в потоках Java 8

В документах Oracle есть несколько вещей, которые я не могу полностью понять:

Operations like forEach and peek are designed for side effects;

Что они подразумевают под «разработанным»? Что особенного в этих двоих? Я могу написать свой код, чтобы любой метод потокового API работал через побочный эффект. Это полностью зависит от меня, насколько я понимаю. Более того, я обычно использую peek() для изменения состояния элемента, а не самого источника, что не делает его с состоянием или подверженным побочным эффектам.

В javadoc для forEach также говорится:

The behavior of this operation is explicitly nondeterministic.

Я понимаю, когда то же самое говорят про findAny, но что недетерминированного в forEach? Любая операция в параллельном потоке не может гарантировать упорядочение, если поток не упорядочен. Почему недетерминизм упоминается только для forEach(и finAny, но это немного другое)?

Для peek и forEach javadoc также содержит:

action may be performed at whatever time and in whatever thread the library chooses

Опять же, почему только там? Почему это не упоминается для остальных операций?


person yuranos    schedule 19.10.2016    source источник
comment
Ну, два пункта вашего вопроса на самом деле отвечают на него. Для обычных промежуточных операций индетерминизм не имеет значения, так как они должны быть свободны от побочных эффектов и не мешать. Для forEach, который «предназначен для побочных эффектов», индетерминизм имеет значение и должен быть задокументирован.   -  person Holger    schedule 19.10.2016
comment
Только от вас зависит, хотите ли вы получить правильный ответ. В спецификации четко указано, что поведенческие параметры, передаваемые большинству потоковых методов, должны быть без сохранения состояния. Это означает, что при наличии побочных эффектов, которые могут повлиять на вычисления, нет гарантии, что вы получите правильный ответ.   -  person Brian Goetz    schedule 19.10.2016
comment
Таким образом, говоря о побочных эффектах, они на самом деле означают, что в реализации peek и forEach есть что-то, что делает их устойчивыми к побочным эффектам, но остальные функции не могут гарантировать то же самое?   -  person yuranos    schedule 03.11.2016


Ответы (1)


Во-первых, изменение состояния объекта также является побочным эффектом, поскольку общее состояние вашей программы изменяется после выполнения вашей лямбды. У вас даже может возникнуть проблема параллелизма, если у вас есть один и тот же объект несколько раз в параллельном потоке. Функция без побочных эффектов — это функция, которая не изменяет состояние программы, и ее возвращаемое значение основано только на ее аргументах. Поскольку другие потоковые операции должны быть без побочных эффектов, нет необходимости указывать, в каком потоке и в какое время они будут выполняться, поскольку это не имеет значения. Но если операция может иметь побочный эффект, это должно быть указано явно.

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

person Tagir Valeev    schedule 19.10.2016
comment
Функция без побочных эффектов — это функция, которая не изменяет состояние программы, и ее возвращаемое значение основано только на ее аргументах. Разве это не определение чистой функции? Отсутствие побочных эффектов означает отсутствие изменения локальных статических переменных, нелокальных переменных, изменяемых ссылочных аргументов или потоков ввода-вывода. Функция может быть свободной от побочных эффектов, но при этом иметь возвращаемое значение, не основанное на ее аргументах. Пример: int f() { return x; } Эта функция не имеет побочных эффектов, но ее возвращаемое значение зависит от нелокальной переменной. - person Vipul Jain; 05.08.2019