Recently I wanted to know how to change a stream into an Iterable. The method in the API that I need to call expects an Iterable.
I found the following solution in [1]:
{
public void evaluate(Session session, Iterable<House> iterable)
{
// do stuff
}
}
public void realEstateEvaluation()
{
Stream<House> housenumbersStream =
housenumbers.stream()
.map(realEstateService::getHouse);
new RealEstateEvaluator().evaluate(getSession(), housenumbersStream::iterator);
}
However, [1] did mention that the result was unreadable. It is confusing that a method reference that provides an Iterator, perhaps accidentally, fulfills the contract for Iterable2.
That's right. Iterable is an interface3, which has three methods, two of which have default implementations. Which means it has one method (iterator()), which means it can be used as a Lambda expression.
I prefer:
{
List<House> houses =
housenumbers.stream()
.map(realEstateService::getHouse)
.collect(Collectors.toList();
new RealEstateEvaluator().evaluate(getSession(), houses);
}
It is a lot more readable. And I am a big believer in the Principle of Least Surprise.
All Collections are Iterables, by the way.
Update 2018-02-23: after reading and evaluating the comment below, I still think using the method reference makes it harder to read, but is much safer to use. Perhaps getting used to using stream::iterator is just a question of time.
References
- [1] LambdaFAQ - How do I turn a stream into an iterable
- http://www.lambdafaq.org/how-do-i-turn-a-stream-into-an-iterable/
- [2] StackOverflow - Why does stream not implement iterable
- https://stackoverflow.com/questions/20129762/why-does-streamt-not-implement-iterablet
- [3] Oracle JavaDoc - Iterable
- https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html?is-external=true