Это один из наиболее интересных недавних вопросов переполнения стека:
Почему Iterable не предоставляет методы stream () и parallelStream ()?
Поначалу может показаться интуитивно понятным сделать преобразование Iterable в Stream простым, поскольку эти два варианта более или менее одинаковы для 90% всех вариантов использования.
Конечно, группа экспертов уделяла большое внимание созданию параллельного интерфейса API Stream , но любой, кто работает с Java каждый день, сразу же заметит, что Stream наиболее полезен в последовательной форме . И Iterable — это просто так. Последовательный поток без каких-либо гарантий в отношении распараллеливания. Таким образом, это было бы интуитивно понятно, если бы мы могли просто написать:
|
1
|
iterable.stream(); |
На самом деле, подтипы Iterable имеют такие методы, например:
|
1
|
collection.stream(); |
Брайан Гетц сам дал ответ на вопрос о переполнении стека . Причины этого упущения коренятся в том факте, что некоторые Iterables могут предпочесть вернуть IntStream вместо Stream . Это действительно кажется очень отдаленной причиной для принятия дизайнерского решения, но, как всегда, сегодняшнее пропущение не означает упущение навсегда. С другой стороны, если бы они сегодня внедрили Iterable.stream() , и это оказалось ошибкой, они не могли бы удалить его снова.
Что ж, примитивные типы в Java — это боль, и в первую очередь они делали всякие плохие вещи с дженериками, а теперь и с Stream , а мы должны написать следующее, чтобы превратить Iterable в Stream :
|
1
|
Stream s = StreamSupport.stream(iterable.spliterator(), false); |
Брайан Гетц утверждает, что это «легко», но я бы не согласился. Как потребитель API, я испытываю большие трения в производительности из-за:
-
StreamSupportэтого бесполезного в противном случае типаStreamSupport. Этот метод вполне можно было бы поместить в интерфейсStream, потому что у нас уже есть методы построенияStream, такие какStream.of(). - Необходимость помнить тонкую разницу между
IteratorиSpliteratorв контексте того, что я считаю, не имеет ничего общего с распараллеливанием. Вполне возможно, что в конечном итогеSpliteratorsстанут популярными, так что это сомнение для магического шара. - На самом деле, я должен повторить информацию, что нечего распараллеливать через логический аргумент
false
Параллелизация действительно имеет такой большой вес в этом новом API, даже если она будет охватывать только около 5% -10% всех операций манипулирования функциональной коллекцией. Хотя последовательная обработка не была главной целью разработки API JDK 8, она действительно является основным преимуществом для всех нас, и трения вокруг API, связанные с последовательной обработкой, должны быть как можно ниже.
Вышеуказанный метод должен был быть только что вызван:
|
1
|
Stream s = Stream.stream(iterable); |
Это может быть реализовано так:
|
1
2
3
|
public static<T> Stream<T> stream(Iterable<T> i) { return StreamSupport.stream(i.spliterator(), false);} |
Очевидно с удобными перегрузками, которые допускают дополнительные специализации, такие как распараллеливание или передача Spliterator
Но опять же, если бы Iterable имел собственный метод по умолчанию stream() , невероятное количество API-интерфейсов было бы намного лучше интегрировано с Java 8 из коробки, даже без явной поддержки Java 8!
Взять, к примеру, JOOQ . jOOQ по-прежнему поддерживает Java 6, поэтому прямая зависимость невозможна. Однако тип ResultQuery в ResultQuery является Iterable . Это позволяет вам использовать такие запросы непосредственно в циклах foreach, как если бы вы писали PL / SQL:
PL / SQL
|
1
2
3
4
5
6
|
FOR book IN ( SELECT * FROM books ORDER BY books.title)LOOP -- Do things with bookEND LOOP; |
Ява
|
1
2
3
4
5
|
for (BookRecord book : ctx.selectFrom(BOOKS).orderBy(BOOKS.TITLE)) { // Do things with book} |
Теперь представьте то же самое в Java 8:
|
1
2
3
|
ctx.selectFrom(BOOKS).orderBy(BOOKS.TITLE) .stream() .map / reduce / findAny, etc... |
К сожалению, вышесказанное в настоящее время невозможно. Конечно, вы можете с нетерпением извлечь все результаты в jOOQ Result , который расширяет List :
|
1
2
3
4
|
ctx.selectFrom(BOOKS).orderBy(BOOKS.TITLE) .fetch() .stream() .map / reduce / findAny, etc... |
Но это еще один метод для вызова (каждый раз), и фактическая семантика потока нарушена, потому что выборка выполняется с нетерпением.
Жаловаться на высоком уровне
Это, конечно, жалоба на высоком уровне, но было бы действительно здорово, если бы будущая версия Java, например Java 9, добавила этот недостающий метод в Iterable API. Опять же, 99% всех вариантов использования будут хотеть возвращать тип Stream , а не тип IntStream . И если они хотят этого по какой-то непонятной причине (гораздо более непонятной, чем многие злые вещи из старых унаследованных API-интерфейсов Java, глядя на ваш Calendar ), то почему бы им просто не объявить метод intStream() . В конце концов, если кто-то достаточно сумасшедший, чтобы написать Iterable<Integer> когда он действительно работает с примитивными типами int , он, вероятно, примет небольшой обходной путь.
| Ссылка: | Очень жаль, что Java 8 не имеет Iterable.stream () от нашего партнера по JCG Лукаса Эдера из блога JAVA, SQL и AND JOOQ . |