如何从迭代器创建 Java 8 Stream?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23439780/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 22:59:42  来源:igfitidea点击:

How to create a Java 8 Stream from an iterator?

javajava-stream

提问by sdenham

Is it possible to create a Stream from an Iterator, in which the sequence of objects is the same as that generated by calling the iterator's next() method repeatedly? The specific case I am thinking of concerns the use of the iterator returned by TreeSet.descendingIterator(), but I can imagine other circumstances in which an iterator, but not the collection it references, is available.

是否可以从迭代器创建一个流,其中对象的序列与通过重复调用迭代器的 next() 方法生成的序列相同?我正在考虑的具体情况与 TreeSet.descendingIterator() 返回的迭代器的使用有关,但我可以想象在其他情况下迭代器可用,而不是它引用的集合。

For example, for a TreeSet<T> tsetwe can write tset.stream()...and get a stream of the objects in that set, in the set's sort order, but what if we want them in a different order, such as that available through using descendingIterator()? I am imagining something like tset.descendingIterator().stream()...or stream( tset.descendingIterator() )..., though neither of these forms are valid.

例如,对于 aTreeSet<T> tset我们可以tset.stream()...按照集合的排序顺序编写和获取该集合中的对象流,但是如果我们希望它们以不同的顺序(例如通过 using 可用的顺序)descendingIterator()怎么办?我正在想象类似tset.descendingIterator().stream()...或 的东西stream( tset.descendingIterator() )...,尽管这两种形式都无效。

采纳答案by andersschuller

For the particular example of NavigableSet.descendingIterator(), I think the simplest way is to use NavigableSet.descendingSet()instead.

对于 的特定示例NavigableSet.descendingIterator(),我认为最简单的方法是使用NavigableSet.descendingSet()

But given you are probably interested in the more general case, the following seems to work:

但鉴于您可能对更一般的情况感兴趣,以下似乎有效:

import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.TreeSet;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public class Streams {
    public static void main(String... args) {
        TreeSet<String> set = new TreeSet<>();
        set.add("C");
        set.add("A");
        set.add("B");

        Iterator<String> iterator = set.descendingIterator();

        int characteristics = Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED;
        Spliterator<String> spliterator = Spliterators.spliteratorUnknownSize(iterator, characteristics);

        boolean parallel = false;
        Stream<String> stream = StreamSupport.stream(spliterator, parallel);

        stream.forEach(System.out::println); // prints C, then B, then A
    }
}

In short, you have to create a Spliteratorfrom the Iteratorfirst using one of the static methods in Spliterators. Then you can create a Streamusing the static methods in StreamSupport.

总之,你必须创建一个SpliteratorIterator第一使用的静态方法之一Spliterators。然后您可以Stream使用StreamSupport.

I don't have that much experience with creating Spliterators and Streams by hand yet, so I can't really comment on what the characteristics should be or what effect they will have. In this particular simple example, it didn't seem to matter whether I defined the characteristics as above, or whether I set it to 0 (i.e. no characteristics). There is also a method in Spliteratorsfor creating a Spliterator with an initial size estimate - I suppose in this particular example you could use set.size(), but if you want to handle arbitrary Iterators I guess this won't be the case. Again, I'm not quite sure what effect it has on performance.

我还没有太多手动创建 Spliterators 和 Streams 的经验,所以我无法真正评论应该具有什么特征或它们将产生什么效果。在这个特别简单的例子中,我是否如上定义特征,或者是否将其设置为 0(即没有特征)似乎并不重要。还有一种方法可以Spliterators用于创建具有初始大小估计的 Spliterator - 我想在这个特定示例中您可以使用set.size(),但是如果您想处理任意迭代器,我想情况并非如此。同样,我不太确定它对性能有什么影响。

回答by Karol Król

static <T> Stream<T> iteratorToFiniteStream(final Iterator<T> iterator) {
    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
}

static <T> Stream<T> iteratorToInfiniteStream(final Iterator<T> iterator) {
    return Stream.generate(iterator::next);
}

回答by Jordan Shurmer

This doesn't create a stream, but Iteratoralso has a method called forEachRemaining:

这不会创建流​​,但Iterator也有一个名为的方法forEachRemaining

someIterator.forEachRemaining(System.out::println);
someIterator.forEachRemaining(s -> s.doSomething());
//etc.

The argument you pass in is a Consumerwhich is the same thing you pass to Stream::forEach.

您传入的参数是一个Consumer,它与您传递给Stream::forEach 的内容相同

Here are the docsfor that method. note that you can't continue the "chain"like you can with a stream. But I've still found this helpful the few times I've wanted a Stream from an Iterator.

这是该方法的文档。请注意,您不能像使用流一样继续“链”。但是我几次想要来自迭代器的 Stream 时,我仍然发现这很有帮助。

回答by lczapski

As it was written by Karol Królfor infinite stream you can use this:

正如Karol Król为无限流编写的那样,您可以使用它:

Stream.generate(iterator::next)

but you can also use it for finite stream with takeWhilesince Java 9

但您也可以将它用于有限流,takeWhile因为 Java 9

Stream.generate(iterator::next).takeWhile((v) -> iterator.hasNext())