How to convert an Iterator to a Stream?
One way is to create a Spliterator
from the Iterator
and use that as a basis for your stream:
Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Stream<String> targetStream = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED),
false);
An alternative which is maybe more readable is to use an Iterable
- and creating an Iterable
from an Iterator
is very easy with lambdas because Iterable
is a functional interface:
Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Iterable<String> iterable = () -> sourceIterator;
Stream<String> targetStream = StreamSupport.stream(iterable.spliterator(), false);
How to create a Java 8 Stream from an iterator?
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.
Make a Stream into an Iterable?
As explained in Why does Stream<T> not implement Iterable<T>?, an Iterable
bears the expectation to be able to provide an Iterator
more than once, which a Stream
can’t fulfill. So while you can create an Iterable
out of a Stream
for an ad-hoc use, you have to be careful about whether attempts to iterate it multiple times could exist.
Since you said, “I need to pass those parts of string as an Iterable
to a specific library”, there is no general solution as the code using the Iterable
is outside your control.
But if you are the one who creates the stream, it is possible to create a valid Iterable
which will simply repeat the stream construction every time an Iterator
is requested:
Iterable<String> lines = () -> "this\nthat\nthe_other".lines().iterator();
This fulfills the expectation of supporting an arbitrary number of iterations, while not consuming more resources than a single stream when being traversed only once.
for(var s: lines) System.out.println(s);
lines.forEach(System.out::println);
System.out.println(String.join("\n", lines));
Convert Iterator to List
Better use a library like Guava:
import com.google.common.collect.Lists;
Iterator<Element> myIterator = ... //some iterator
List<Element> myList = Lists.newArrayList(myIterator);
Another Guava example:
ImmutableList.copyOf(myIterator);
or Apache Commons Collections:
import org.apache.commons.collections.IteratorUtils;
Iterator<Element> myIterator = ...//some iterator
List<Element> myList = IteratorUtils.toList(myIterator);
How do I convert an iterator into a stream on success or an empty stream on failure?
Rust is a statically typed language which means that the return type of a function has to be a single type, known at compile time. You are attempting to return multiple types, decided at runtime.
The closest solution to your original is to always return the Unfold
stream:
fn resolve(addrs: impl ToSocketAddrs) -> impl Stream<Item = SocketAddr, Error = ()> {
stream::unfold(addrs.to_socket_addrs(), |r| {
match r {
Ok(mut iter) => iter.next().map(|addr| future::ok((addr, Ok(iter)))),
Err(_) => None,
}
})
}
But why reinvent the wheel?
futures::stream::iter_ok
Converts an
Iterator
into aStream
which is always ready to yield the next value.
Subsequent versions of the futures crate implement Stream
for Either
, which makes this very elegant:
fn resolve(addrs: impl ToSocketAddrs) -> impl Stream<Item = SocketAddr, Error = ()> {
match addrs.to_socket_addrs() {
Ok(iter) => stream::iter_ok(iter).left_stream(),
Err(_) => stream::empty().right_stream(),
}
}
It's straightforward to backport this functionality to futures 0.1 (maybe someone should submit it as a PR for those who are stuck on 0.1...):
enum MyEither<L, R> {
Left(L),
Right(R),
}
impl<L, R> Stream for MyEither<L, R>
where
L: Stream,
R: Stream<Item = L::Item, Error = L::Error>,
{
type Item = L::Item;
type Error = L::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
match self {
MyEither::Left(l) => l.poll(),
MyEither::Right(r) => r.poll(),
}
}
}
trait EitherStreamExt {
fn left_stream<R>(self) -> MyEither<Self, R>
where
Self: Sized;
fn right_stream<L>(self) -> MyEither<L, Self>
where
Self: Sized;
}
impl<S: Stream> EitherStreamExt for S {
fn left_stream<R>(self) -> MyEither<Self, R> {
MyEither::Left(self)
}
fn right_stream<L>(self) -> MyEither<L, Self> {
MyEither::Right(self)
}
}
Even better, use the fact that Result
is an iterator and Stream::flatten
exists:
fn resolve(addrs: impl ToSocketAddrs) -> impl Stream<Item = SocketAddr, Error = ()> {
stream::iter_ok(addrs.to_socket_addrs())
.map(stream::iter_ok)
.flatten()
}
Or if you really want to print errors:
fn resolve(addrs: impl ToSocketAddrs) -> impl Stream<Item = SocketAddr, Error = ()> {
stream::once(addrs.to_socket_addrs())
.map(stream::iter_ok)
.map_err(|e| eprintln!("err: {}", e))
.flatten()
}
See also:
- Conditionally return empty iterator from flat_map
- Conditionally iterate over one of several possible iterators
- What is the correct way to return an Iterator (or any other trait)?
Converting an AutoCloseable, Iterable class into a Stream
As stated in the javadoc, BaseStream.onClose()
"Returns an equivalent stream with an additional close handler":
public class WorkingExample {
public static void main(final String[] args) {
MyCursor cursor = new MyCursor();
try (Stream<String> stream = StreamSupport.stream(cursor.spliterator(), false)
.onClose(cursor::close)) {
stream.forEach(System.out::println);
}
}
}
will call MyCursor.close()
as desired.
Convert enhance loop with inner iterator to stream
One of possible solutions can be introducing an intermediate class to store intermediate values (assuming Month
is an enum
):
private static Map<Month, Integer> sumGroupingByMonth(final Collection<Scooter> scooters) {
@AllArgsConstructor
final class Intermediate {
final int newVal;
final Day rentalDay;
}
return scooters.stream()
.flatMap(scooter -> {
final int newVal = scooter.getMileage() * scooter.getMileageRate();
return scooter.getRentalDays()
.stream()
.map(day -> new Intermediate(newVal, day));
})
.collect(Collectors.groupingBy(intermediate -> intermediate.rentalDay.getMonth(), Collectors.summingInt(intermediate -> intermediate.newVal)));
}
I find this code pretty complex: closures, explicit intermediate state, function scoping, intermediate objects, and probably the following could be both more simple and faster?
private static int[] sumGroupingByMonth(final Iterable<Scooter> scooters) {
final int[] data = new int[12];
for ( final Scooter scooter : scooters ) {
final int newVal = scooter.getMileage() * scooter.getMileageRate();
for ( final Day rentalDay : scooter.getRentalDays() ) {
data[rentalDay.getMonth().ordinal()] += newVal;
}
}
return data;
}
Related Topics
Java Thread.Sleep Puts Swing UI to Sleep Too
How to Pass a Parameter to a Java Thread
Differencebetween Dynamic and Static Polymorphism in Java
Practical Uses for Atomicinteger
No @Xmlrootelement Generated by Jaxb
How to Resize an Image Using Java
How to Return a JSON Object from a Java Servlet
In Java, How to Parse Xml as a String Instead of a File
Java Sending and Receiving File (Byte[]) Over Sockets
Easiest Way to Merge a Release into One Jar File
Collections.Sort with Multiple Fields
Read Url to String in Few Lines of Java Code
Java.Util.Date Format Conversion Yyyy-Mm-Dd to Mm-Dd-Yyyy
List of All Special Characters That Need to Be Escaped in a Regex