Stream做为Java8的新特性之一,他与Java IO包中的InputStream和OutputStream彻底不是一个概念。Java8中的Stream是对集合功能的一种加强,主要用于对集合对象进行各类很是便利高效的聚合和大批量数据的操做。结合Lambda表达式能够极大的提升开发效率和代码可读性。java
假设咱们须要把一个集合中的全部形状设置成红色,那么咱们能够这样写git
for (Shape shape : shapes){
shape.setColor(RED)
}
若是使用Java8扩展后的集合框架则能够这样写:github
shapes.foreach(s -> s.setColor(RED));
第一种写法咱们叫外部迭代,for-each调用shapes
的iterator()
依次遍历集合中的元素。这种外部迭代有一些问题:markdown
上面这两个问题咱们会在后面的文章中逐步解答。数据结构
shapes.stream() .filter(s -> s.getColor() == BLUE) .forEach(s -> s.setColor(RED));在`Collection`上调用`stream()`会生成该集合元素的流,接下来`filter()`操做会产生只包含蓝色形状的流,最后,这些蓝色形状会被`forEach`操做设为红色。 若是咱们想把蓝色的形状提取到新的List里,则能够:
List<Shape> blue = shapes.stream() .filter(s -> s.getColor() == BLUE) .collect(Collectors.toList());`collect()`操做会把其接收的元素汇集到一块儿(这里是List),`collect()`方法的参数则被用来指定如何进行汇集操做。在这里咱们使用`toList()`以把元素输出到List中。 若是每一个形状都被保存在`Box`里,而后咱们想知道哪一个盒子至少包含一个蓝色形状,咱们能够这么写:
Set<Box> hasBlueShape = shapes.stream() .filter(s -> s.getColor() == BLUE) .map(s -> s.getContainingBox()) .collect(Collectors.toSet());`map()`操做经过映射函数(这里的映射函数接收一个形状,而后返回包含它的盒子)对输入流里面的元素进行依次转换,而后产生新流。 若是咱们须要获得蓝色物体的总重量,咱们能够这样表达:
int sum = shapes.stream()
.filter(s -> s.getColor() == BLUE)
.mapToInt(s -> s.getWeight())
.sum();
filter()
和map()
这样的操做既能够被急性求值(以filter()
为例,急性求值须要在方法返回前完成对全部元素的过滤),也能够被惰性求值(用Stream
表明过滤结果,当且仅当须要时才进行过滤操做)在实际中进行惰性运算能够带来不少好处。好比说,若是咱们进行惰性过滤,咱们就能够把过滤和流水线里的其它操做混合在一块儿,从而不须要对数据进行多遍遍历。相相似的,若是咱们在一个大型集合里搜索第一个知足某个条件的元素,咱们能够在找到后直接中止,而不是继续处理整个集合。(这一点对无限数据源是很重要,惰性求值对于有限数据源起到的是优化做用,但对无限数据源起到的是决定做用,没有惰性求值,对无限数据源的操做将没法终止)框架
对于filter()
和map()
这样的操做,咱们很天然的会把它当成是惰性求值操做,不过它们是否真的是惰性取决于它们的具体实现。另外,像sum()
这样生成值的操做和forEach()
这样产生反作用的操做都是自然急性求值,由于它们必需要产生具体的结果。ide
咱们拿下面这段代码举例:函数
int sum = shapes.stream()
.filter(s -> s.getColor() == BLUE)
.mapToInt(s -> s.getWeight())
.sum();
这里的filter()
和map()
都是惰性的,这就意味着在调用sum()
以前不会从数据源中提取任何元素。在sum()
操做以后才会把filter()
、map()
和sum()
放在对数据源一次遍历中。这样能够大大减小维持中间结果所带来的开销。性能
前面长篇大论的介绍概念实在太枯燥,为了方便你们理解咱们用Streams API来实现一个具体的业务场景。优化
假设咱们有一个房源库项目,这个房源库中有一系列的小区,每一个小区都有小区名和房源列表,每套房子又有价格、面积等属性。如今咱们须要筛选出含有100平米以上房源的小区,并按照小区名排序。
咱们先来看看不用Streams API如何实现:
List<Community> result = new ArrayList<>();
for (Community community : communities) {
for (House house : community.houses) {
if (house.area > 100) {
result.add(community);
break;
}
}
}
Collections.sort(result, new Comparator<Community>() {
@Override
public int compare(Community c1, Community c2) {
return c1.name.compareTo(c2.name);
}
});
return result;
若是使用Streams API:
return communities.stream()
.filter(c -> c.houses.stream().anyMatch(h -> h.area>100))
.sorted(Comparator.comparing(c -> c.name))
.collect(Collectors.toList());
若是你喜欢个人文章,就关注下个人知乎专栏或者在 GitHub 上添个 Star 吧!