У меня есть интерфейс, который возвращает java.lang.Iterable<T>
.
Я хотел бы обработать этот результат с помощью Java 8 Stream API.
Однако Iterable не может "Поток".
Как лучше использовать потоки (без преобразования Iterable в List)?
У меня есть интерфейс, который возвращает java.lang.Iterable<T>
.
Я хотел бы обработать этот результат с помощью Java 8 Stream API.
Однако Iterable не может "Поток".
Как лучше использовать потоки (без преобразования Iterable в List)?
Там гораздо лучший ответ, чем использование spliteratorUnknownSize
напрямую, что также легче и получает лучший результат. Iterable
имеет метод spliterator()
, поэтому вы должны просто использовать его для получения разделителя. В худшем случае, тот же код (реализация по умолчанию использует spliteratorUnknownSize
), но в более общем случае, когда ваш Iterable
уже является коллекцией, вы получите лучший разделитель и, следовательно, лучшую производительность потока ( может быть, даже хороший parallelism.) Его также меньше кода:
StreamSupport.stream(iterable.spliterator(), false)
.filter(...)
.moreStreamOps(...);
Как вы можете видеть, получение потока из Iterable (см. Почему Iterable <T> не предоставляет методы stream() и parallelStream()?) не является очень болезненный.
Если вы можете использовать библиотеку Guava, начиная с версии 21, вы можете использовать
Streams.stream(iterable)
Вы можете легко создать Stream
из Iterable
или Iterator
:
public static <T> Stream<T> stream(Iterable<T> iterable) {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
iterable.iterator(),
Spliterator.ORDERED
),
false
);
}
Я хотел бы предложить использовать библиотеку JOOL, она скрывает магию spliterator за вызовом Seq.seq(iterable), а также предоставляет целую кучу дополнительных полезных функциональность.
Я создал этот класс:
public class Streams {
/**
* Converts Iterable to stream
*/
public static <T> Stream<T> streamOf(final Iterable<T> iterable) {
return toStream(iterable, false);
}
/**
* Converts Iterable to parallel stream
*/
public static <T> Stream<T> parallelStreamOf(final Iterable<T> iterable) {
return toStream(iterable, true);
}
private static <T> Stream<T> toStream(final Iterable<T> iterable, final boolean isParallel) {
return StreamSupport.stream(iterable.spliterator(), isParallel);
}
}
Я думаю, что он отлично читается, потому что вам не нужно думать о spliterators и booleans (isParallel).
Очень простая работа для этой проблемы заключается в создании интерфейса Streamable<T>
, расширяющего Iterable<T>
, который содержит метод default <T> stream()
.
interface Streamable<T> extends Iterable<T> {
default Stream<T> stream() {
return StreamSupport.stream(spliterator(), false);
}
}
Теперь любой из ваших Iterable<T>
можно создать тривиально, просто объявив их implements Streamable<T>
вместо Iterable<T>
.
Если вы используете Vavr (ранее известный как Javaslang), это может быть так же просто, как:
Iterable i = //...
Stream.ofAll(i);
Итак, как еще один ответ, упомянутый Гуава, поддерживает это:
Streams.stream(iterable);
Я хочу подчеркнуть, что реализация делает что-то немного отличное от других предложенных ответов. Если Iterable
имеет тип Collection
, он их произносит.
public static <T> Stream<T> stream(Iterable<T> iterable) {
return (iterable instanceof Collection)
? ((Collection<T>) iterable).stream()
: StreamSupport.stream(iterable.spliterator(), false);
}
public static <T> Stream<T> stream(Iterator<T> iterator) {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(iterator, 0),
false
);
}