Почему поток не реализует Iterable?
в Java 8 класс Поток, которые на удивление метод
Iterator<T> iterator()
таким образом, вы ожидаете, что он реализует интерфейс Iterable, что требует именно этого метода, но это не так.
когда я хочу перебирать поток с помощью цикла foreach, я должен сделать что-то вроде
public static Iterable<T> getIterable(Stream<T> s) {
return new Iterable<T> {
@Override
public Iterator<T> iterator() {
return s.iterator();
}
};
}
for (T element : getIterable(s)) { ... }
Я что-то пропустил?
9 ответов:
там уже люди спрашивали то же самое в списке рассылки☺. Основная причина заключается в том, что Iterable также имеет повторную итерацию семантики, а Stream-нет.
Я думаю, что главная причина в том, что
Iterableподразумевает возможность повторного использования, тогда какStreamэто то, что может быть использован только один раз - больше какIterator.если
StreamextendedIterableтогда существующий код может быть удивлен, когда он получаетIterableЧто выдаетExceptionв во второй раз они делаютfor (element : iterable).
преобразование
StreamдоIterable, вы можете сделатьStream<X> stream = null; Iterable<X> iterable = stream::iteratorпередать
Streamк методу, который ожидаетIterable,void foo(Iterable<X> iterable)просто
foo(stream::iterator)однако это, вероятно, выглядит смешно; это может быть лучше, чтобы быть немного более явным
foo( (Iterable<X>)stream::iterator );
Я хотел бы отметить, что
StreamExреализуетIterable(иStream), а также множество других чрезвычайно удивительных функций, отсутствующих вStream.
kennytm описано почему небезопасно лечить
StreamкакIterableи Чжун Юй предложил обходной путь что позволяет использоватьStreamа вIterable, хотя и небезопасным образом. Можно получить лучшее из обоих миров: многоразовыйIterableСStreamЭто соответствует всем гарантиям, сделаннымIterableспецификация.Примечание:
SomeTypeздесь не параметр типа--вам нужно заменить его на правильный тип (например,String) или прибегнуть к рефлексииStream<SomeType> stream = ...; Iterable<SomeType> iterable = stream.collect(toList()):есть один главный недостаток:
преимущества ленивой итерации будут потеряны. Если вы планируете немедленно выполнить итерацию по всем значениям в текущем потоке, любые накладные расходы будут незначительными. Однако если вы планируете итерацию только частично или в другом потоке, эта немедленная и полная итерация может иметь непреднамеренные последствия.
большим преимуществом, конечно, является то, что вы можете повторное использование
Iterable, тогда как(Iterable<SomeType>) stream::iteratorпозволит только однократное использование. Если получающий код будет повторяться над коллекцией несколько раз, это не только необходимо, но и, вероятно, полезно для производительности.
Вы можете использовать поток
forпетли следующим образом:Stream<T> stream = ...; for (T x : (Iterable<T>) stream::iterator) { ... }(Run вот этот фрагмент)
(Это использует приведение функционального интерфейса Java 8.)
(это описано в некоторых комментариях выше (например,Александр Дубинский), но я хотел вытащить его в ответ, чтобы сделать его более заметным.)
Если вы не против использовать сторонние библиотеки Циклоп-реагировать определяет поток, который реализует как поток, так и итерацию и также воспроизводится (решение проблемы kennytm описано).
Stream<String> stream = ReactiveSeq.of("hello","world") .map(s->"prefix-"+s);или
Iterable<String> stream = ReactiveSeq.of("hello","world") .map(s->"prefix-"+s); stream.forEach(System.out::println); stream.forEach(System.out::println);[раскрытие я ведущий разработчик cyclops-react]
не идеально, но будет работать:
iterable = stream.collect(Collectors.toList());не идеально, потому что он будет извлекать все элементы из потока и помещать их в это
List, что не совсем то, чтоIterableиStreamпро. Они должны быть лень.
вы можете перебирать все файлы в папке с помощью
Stream<Path>такой:Path path = Paths.get("..."); Stream<Path> files = Files.list(path); for (Iterator<Path> it = files.iterator(); it.hasNext(); ) { Object file = it.next(); // ... }
Streamне реализуетIterable. Общее пониманиеIterableэто все, что можно повторить, часто снова и снова.Streamможет не воспроизводиться.единственный обходной путь, который я могу придумать, где итерируемый на основе потока также воспроизводится,-это воссоздать поток. Я использую
Supplierниже, чтобы создать новый экземпляр потока, каждый раз создается новый итератор.Supplier<Stream<Integer>> streamSupplier = () -> Stream.of(10); Iterable<Integer> iterable = () -> streamSupplier.get().iterator(); for(int i : iterable) { System.out.println(i); } // Can iterate again for(int i : iterable) { System.out.println(i); }