Java8:Stream

背景:
集合是Java中使用最多的API。几乎每个Java应用程序都会制造和处理集合。集合对于很多编程任务来说都是非常基本的:它们可以让你把数据分组并加以处理。
但是Java8之前,集合操作还是算不上完美。
比如,以下SQL查询语句就可以选出热量较低的菜肴名称:

SELECT name FROM dishes WHERE calorie < 400
  1. 但是Java集合中,你需要自己实现迭代器根据菜肴的属性进行筛选。

  2. 要是要处理大量元素又该怎么办呢?为了提高性能,你需要并行处理,并利用多核架构。但写并行代码比用迭代器还要复杂,而且调试起来也够受的!

流是Java API的新成员

  • 允许你以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现)。
  • 流还可以透明地并行处理,你无需写任何多线程代码了!

下面两段代码都是用来返回低热量的菜肴名称的,并按照卡路里排序,一个是用Java 7写的,另一个是用Java 8的流写的。

// java 7
List<Dish> lowCaloricDishes = new ArrayList<>();

// 用累加器筛选元素
for(Dish d: menu){
    if(d.getCalories() < 400){
        lowCaloricDishes.add(d);
    }
}
// 用匿名类对菜肴排序
Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
    public int compare(Dish d1, Dish d2){
        return Integer.compare(d1.getCalories(), d2.getCalories());
    }
});

List<String> lowCaloricDishesName = new ArrayList<>();

// 处理排序后的菜名列表
for(Dish d: lowCaloricDishes){
        lowCaloricDishesName.add(d.getName());
}

在这段代码中,你用了一个“垃圾变量”lowCaloricDishes。它唯一的作用就是作为一次性的中间容器。

在Java 8中,实现的细节被放在它本该归属的库里了。

// java8
// 静态导包 
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
List<String> lowCaloricDishesName =menu.stream()
                    .filter(d -> d.getCalories() < 400)// 选出400卡路里以下的菜肴
                    .sorted(comparing(Dish::getCalories))// 按照卡路里排序
                    .map(Dish::getName)// 提取菜肴的名称
                    .collect(toList());// 将所有名称保存在List中

为了利用多核架构并行执行这段代码,你只需要把stream()换成parallelStream():

List<String> lowCaloricDishesName =menu.parallelStream()
                        .filter(d -> d.getCalories() < 400)
                        .sorted(comparing(Dishes::getCalories))
                        .map(Dish::getName)
                        .collect(toList());

这样写的一个好处:
1. 代码是以声明性方式写的:说明想要完成什么(筛选热量低的菜肴)而不是说明如何实现一个操作(利用循环和if条件等控制流语句)。
2. 你可以把几个基础操作链接起来,来表达复杂的数据处理流水线,同时保持代码清晰可读。filter的结果被传给了sorted方法,再传给map方法,最后传给collect方法。

因为filter、sorted、map和collect等操作是与具体线程模型无关的高层次构件,所以它们的内部实现可以是单线程的,也可能透明地充分利用你的多核架构!在实践中,这意味着你用不着为了让某些数据处理任务并行而去操心线程和锁了,Stream API都替你做好了!

总结一下,Java 8中的Stream API可以让你写出这样的代码:

  • 声明性——更简洁,更易读
  • 可复合——更灵活
  • 可并行——性能更好

流让你可以简洁地表达复杂的数据处理查询。此外,流可以透明地并行化。以下是你应掌握的关键概念。

 Streams API可以表达复杂的数据处理查询。

 你可以使用filter、distinct、skip和limit对流做筛选和切片。

 你可以使用map和flatMap提取或转换流中的元素。

 你可以使用findFirst 和findAny 方法查找流中的元素。你可以用allMatch 、noneMatch和anyMatch方法让流匹配给定的谓词。

 这些方法都利用了短路:找到结果就立即停止计算;没有必要处理整个流。

 你可以利用reduce方法将流中所有的元素迭代合并成一个结果,例如求和或查找最大元素。

 filter和map等操作是无状态的,它们并不存储任何状态。reduce等操作要存储状态才能计算出一个值。sorted和distinct等操作也要存储状态,因为它们需要把流中的所有元素缓存起来才能返回一个新的流。这种操作称为有状态操作。

 流有三种基本的原始类型特化:IntStream、DoubleStream和LongStream。它们的操作也有相应的特化。

 流不仅可以从集合创建,也可从值、数组、文件以及iterate与generate等特定方法创建。

 无限流是没有固定大小的流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值