it-swarm.com.ru

Преобразуйте Iterable в Stream, используя Java 8 JDK

У меня есть интерфейс, который возвращает Java.lang.Iterable<T>.

Я хотел бы манипулировать этим результатом, используя Java 8 Stream API.

Однако Iterable не может "течь".

Любая идея, как использовать Iterable в качестве потока без преобразования его в список?

373
rayman

Есть гораздо лучший ответ, чем прямое использование spliteratorUnknownSize, что проще и дает лучший результат. Iterable имеет метод spliterator(), так что вы должны просто использовать его, чтобы получить свой сплитератор. В худшем случае это тот же код (реализация по умолчанию использует spliteratorUnknownSize), но в более общем случае, когда ваше Iterable уже является коллекцией, вы получите лучший сплитератор и, следовательно, лучшую производительность потока (возможно, даже хороший параллелизм ). Это также меньше кода:

StreamSupport.stream(iterable.spliterator(), false)
             .filter(...)
             .moreStreamOps(...);

Как видите, получение потока от Iterable (см. Также этот вопрос ) не очень болезненно.

511
Brian Goetz

Если вы можете использовать библиотеку Guava, начиная с версии 21, вы можете использовать

Streams.stream(iterable)
57
numéro6

Вы можете легко создать Stream из Iterable или Iterator:

public static <T> Stream<T> stream(Iterable<T> iterable) {
    return StreamSupport.stream(
        Spliterators.spliteratorUnknownSize(
            iterable.iterator(),
            Spliterator.ORDERED
        ),
        false
    );
}
22
nosid

Я хотел бы предложить использовать библиотеку JOOL , она скрывает магию сплитератора за вызовом Seq.seq (iterable), а также предоставляет целый ряд дополнительных полезных функций.

9
Shaggie

Так что в качестве другого ответа упоминается, что Гуава поддерживает это с помощью:

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
  );
}
3
Alex

Я создал этот класс:

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);
    }
}

Я думаю, что он отлично читается, потому что вам не нужно думать о разделителях и логических значениях (isParallel).

3
g-t

Очень простой способ обойти эту проблему - создать интерфейс Streamable<T>, расширяющий Iterable<T>, который содержит метод default <T> stream().

interface Streamable<T> extends Iterable<T> {
    default Stream<T> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
}

Теперь любой из ваших Iterable<T>s можно легко преобразовать, просто объявив их implements Streamable<T> вместо Iterable<T>.

3
OldCurmudgeon

Если вы используете Vavr (ранее известный как Javaslang), это может быть так просто:

Iterable i = //...
Stream.ofAll(i);
0
Grzegorz Piwowarek