java8新特性(三):Stream流的概念

流就是让程序员可以用声明式编程来处理集合数据的java接口,简单来说你可以把它看成是遍历数据集的高级迭代器,可以透明的并行处理,所以不需要程序员再写任何多线程代码了。

 

java7 之前(指令式编程)

List<Dish> menu = new ArrayList<>();
List<Dish> lowCaloricDishes = new ArrayList<>();
//过滤,低热量菜单
for(Dish dish: menu){
    if(dish.getColories() < 400){
        lowCaloricDishes.add(dish);
    }
}
//排序
Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
    @Override
    public int compare(Dish o1, Dish o2) {
        return Integer.compare(o1.getColories() , o2.getColories());
    }
});

//属性抽取,获取低热量菜单的名字
List<String> lowCaloricDishNames = new ArrayList<>();
for(Dish dish: lowCaloricDishes){
    lowCaloricDishNames.add(dish.getName());
}

 

java8 (声明式编程)

List<String> lowCaloricDishesName =menu.stream()

.filter(d -> d.getCalories() < 400)

.sorted(comparing(Dishes::getCalories))

.map(Dish::getName)

.collect(toList());

 

如果想使用多线程,只需要将stream() 改成parallelStream()就可以了

List<String> lowCaloricDishesName =menu.parallelStream()

.filter(d -> d.getCalories() < 400)

.sorted(comparing(Dishes::getCalories))

.map(Dish::getName)

.collect(toList());

 

看到这两个例子Stream带来的优点已经显而易见了,

  1. 申明式的代码,你只需要写你想做什么, 而不再需要写怎么去做,这样做代码会更加简洁,更加容易阅读,而且不容易出错,因为我们都知道代码越少BUG就越少,唯一的缺点就是如果你们公司考核需要统计代码行数的话那你就惨了。
  2. 可以将多个操作组合起来,代码更具有灵活性。
  3. 因为filter,sorted,map和collect等操作是与线程模型无关的高层次的代码封装,所以他们的底层实现可以是单线程的也可以是多线程的,程序员再也不用操心多线程的事了,这一切Stream API都为你做好了。

 

 

流的执行

java8新特性(三):Stream流的概念

 

 

 

流就是支持数据处理操作的来自某个源的元素序列。

1.流是元素的序列,所以可以通过流的API来访问它的元素。

2.流会使用一个提供数据的源,这个源可以是集合,也可是数组,或者是文件或者是网络资源,可以是有限的,也可以是无限的。

3.流支持大部分类似数据库的操作,比如过滤,映射,分组,查找,匹配,排序等等,在没有流之前想要把存储过程改成Java代码是很困难的,但是有了流之后想要做这个事情就简单多了。流的操作可以是顺序的,也可以是并行的。

 

集合是内存中的数据结构,所有的值都是已经计算好的。

流是一个概念上的数据结构,它里面的元素的值是在使用到的时候才计算出来的。

集合是关于数据的, 流是关于计算的。

集合就像是池塘里面的水, 你可以反复使用,流就像从你面前流过的小溪,它只能被消费一次,一去不复返。

从哲学上讲,集合是散布于空间的一组数据,而流是散布于时间的一组数据。

集合是外部迭代,外部迭代是每操作一次就要迭代循环一次;流是内部迭代,所有的操作只需要一次迭代就可以完成。

 

java8新特性(三):Stream流的概念

集合就像是DVD中的电影,你可以快进,可以后退, 可以跳跃到你想看的任何地方。 流就先是看在线观直播,它只能被顺序的观看,并且只能看一次。

 

 

流的运算分为中间运算和终端运算。

中间运算返回的值还是一个流对象,终端运算返回的值可以是一个集合一个数值或者没有返回值。

中间操作实际上并未有对流进行任何操作,只是告诉流将要进行什么操作; 只有终端操作才会真正的对流进行迭代运算,将所有的中间操作组合在一起通过一次迭代执行全部的运算。

 

 

中间操作

操作 类型 返回值 操作参数 函数描述器
filter Intermediate Stream<T> Predicate<T> T -> boolean
map Intermediate Stream<R> Function<T, R> T -> R
limit Intermediate Stream<T>    
sorted Intermediate Stream<T> Comparator<T> (T, T) -> int
distinct Intermediate Stream<T>    

 

 

终端操作

操作 类型 目的
forEach Terminal Consumes each element from a stream and applies a lambda to each of them. The operation returns void.
count Terminal Returns the number of elements in a stream. The operation returns a long.
collect Terminal Reduces the stream to create a collection such as a List, a Map, or even anInteger.