Chapter 5. Working with streams
This chapter covers
- Filtering, slicing, and mapping
- Finding, matching, and reducing
- Using numeric streams (primitive stream specializations)
- Creating streams from multiple sources
- Infinite streams
In the previous chapter, you saw that streams let you move from external iteration to internal iteration. Instead of writing code, as follows, where you explicitly manage the iteration over a collection of data (external iteration),
List<Dish> vegetarianDishes = new ArrayList<>(); for(Dish d: menu) { if(d.isVegetarian()){ vegetarianDishes.add(d); } }
you can use the Streams API (internal iteration), which supports the filter and collect operations, to manage the iteration over the collection of data for you. All you need to do is pass the filtering behavior as argument to the filter method:
import static java.util.stream.Collectors.toList; List<Dish> vegetarianDishes = menu.stream() .filter(Dish::isVegetarian) .collect(toList());
This different way of working with data is useful because you let the Streams API manage how to process the data. As a consequence, the Streams API can work out several optimizations behind the scenes. In addition, using internal iteration, the Streams API can decide to run your code in parallel. Using external iteration, this isn’t possible because you’re committed to a single-threaded step-by-step sequential iteration.