Позвольте мне предложить простое правило:
Stream
, который передается в качестве аргумента метода или возвращается как возвращаемое значение метода должен быть хвост из несогласованного трубопровода.
Это, вероятно, так очевидно для тех из нас, кто работал над потоками, которые мы никогда не удосужились записать.Но это, вероятно, не очевидно для людей, приближающихся к потокам в первый раз, поэтому, вероятно, стоит обсудить.
Главное правило распространяется на Streams API package documentation: поток может иметь не более одной операции терминала. Как только это будет прекращено, запрещается добавлять какие-либо промежуточные или терминальные операции.
Другое правило состоит в том, что поточные трубопроводы должны быть линейными; у них не может быть филиалов. Это не очень четко документировано, но упоминается в Stream class documentation о двух третях пути вниз. Это означает, что незаконно добавлять промежуточную или терминальную операцию в поток, если это не последняя операция в конвейере.
Большинство методов потока являются промежуточными или терминальными операциями. Если вы попытаетесь использовать один из них в потоке, который завершен или это не последняя операция, вы довольно быстро узнаете, получив IllegalArgumentException
. Иногда это случается, но я думаю, что когда люди получат идею о том, что конвейер должен быть линейным, они учатся избегать этой проблемы, и проблема уходит. Я думаю, что это довольно легко для большинства людей понять; он не должен требовать сдвига парадигмы.
Как только вы это понимаете, ясно, что если вы собираетесь передать экземпляр Stream
другому фрагменту кода - либо передав его в качестве аргумента, либо вернув его вызывающему абоненту - он должен быть источника потока или последней промежуточной операции в конвейере. То есть, это должен быть хвост нескончаемого трубопровода.
Другими словами: мне кажется, что если API возвращает поток, общее мышление должно состоять в том, что все взаимодействие с ним должно заканчиваться в непосредственном контексте. Запрещается пропускать поток вокруг.
Я думаю, что это слишком ограничительный. Пока вы придерживаетесь правила, которое я предлагал, вы должны быть свободны передавать поток вокруг столько, сколько хотите. Действительно, существует множество вариантов использования для получения потока откуда-то, его изменения и передачи. Вот несколько примеров.
1) Откройте текстовый файл, содержащий текстовое представление POJO на каждой строке. Позвоните по телефону File.lines()
, чтобы получить Stream<String>
. Сопоставьте каждую строку с экземпляром POJO и возвращайте вызывающему абоненту Stream<POJO>
. Вызывающий может применить фильтр или операцию сортировки и вернуть поток своему вызывающему.
2) Учитывая Stream<POJO>
, вы можете иметь веб-интерфейс, позволяющий пользователю предоставлять комплексный набор критериев поиска. (К примеру, рассмотрим торговый сайт с большим количеством сортировки и параметров фильтрации.) Вместо составления большого сложного трубопровода в коде, вы можете иметь метод, как следующие:
Stream<POJO> applyCriteria(Stream<POJO>, SearchCriteria)
который бы поток, применять критерии поиска, добавляя различные фильтры и, возможно, сортировать или выполнять отдельные операции и возвращать полученный поток вызывающему.
Из этих примеров, я надеюсь, вы увидите, что существует значительная гибкость в передаче потоков вокруг, поскольку то, что вы проходите, всегда является хвостом нескончаемого конвейера.
Пожалуйста, подумайте о повторном открытии вопроса - я объяснил, почему я думаю, что это имеет значение. – Vitaliy