How to create a Java 8 Stream from an iterator?

后端 未结 4 1124
隐瞒了意图╮
隐瞒了意图╮ 2020-12-14 01:14

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 s

相关标签:
4条回答
  • 2020-12-14 01:35

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

    Stream.generate(iterator::next)
    

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

    Stream.generate(iterator::next).takeWhile((v) -> iterator.hasNext())
    
    0 讨论(0)
  • 2020-12-14 01:43

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

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

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

    Here are the docs for 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.

    0 讨论(0)
  • 2020-12-14 01:47
    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);
    }
    
    0 讨论(0)
  • 2020-12-14 01:58

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

    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 Spliterator from the Iterator first using one of the static methods in Spliterators. Then you can create a Stream using the static methods in 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 Spliterators for 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.

    0 讨论(0)
提交回复
热议问题