Это один из наиболее интересных недавних вопросов переполнения стека:
Почему 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 book END 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 . |