Lambda中流什么是
流-stream可以粗略的理解为Java中的集合,但和集合还有一点区别。
流支持对数据集合进行各类操作,其能做的操作和集合类似,也是对一组数据进行操作,其特性更像是数据库的增删改查语句,例如我要查询班级中数学成绩大于90分的同学列表,SQL类似:
select * from 班级 where 数学 > 90
通过上面的语句,就能获取一个经过过滤的集合,流相当于持有一个全班的集合,然后进行数学分数过滤,最终得到数学成绩大于90的同学的一个新的集合,我们用集合可以完成,用SQL能够完成,用流同样能够完成,那么集合和流的具体区别在哪里呢?
流和集合的区别
1、集合与流之间的差异就在于什么时候进行计算
集合是一个内存中的数据结构,它包含数据结构中目前所有的值——集合中的每个元素都得先算出来才能添加到集合中;
流则是在概念上固定的数据结构(你不能添加或删除元素),其元素则是按需计算的。按需生成。这是一种生产者-消费者的关系。从另一个角度来说,流就像是一个延迟创建的集合:只有在消费者要求的时候才会计算值(用管理学的话说这就是需求驱动,甚至是实时制造)。流的整个特性总结就是:使用时才计算,按需计算。
2、集合是外部迭代,流是内部迭代
整个我们稍后从demo就能看到效果。
我们先构造一个Student类,如下:
package com.itzhimei.study.lambda.stream;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
@Data
@ToString
@Builder
public class Student {
//班级id
private Integer classId;
//学号
private Integer no;
//姓名
private String name;
//年龄
private Integer age;
//数学
private Double math;
//语文
private Double chinese;
//英语
private Double english;
//总分
private Double score;
}
接下来我们实现demo代码:
package com.itzhimei.study.lambda.stream;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class StreamTest1 {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
String[] names = {"小明","小华","小志","小东","小李","小张","小王","小周","小吴","小郑"};
for(int i=0; i<10; i++) {
Student student = Student.builder()
.name(names[i])
.age(12+i/5)
.no(i+1)
.math(85d+i).build();
list.add(student);
}
//初始化数据
System.out.println("======初始化数据:======");
list.forEach(System.out::println);
//集合过滤90分的
List<Student> math90 = new ArrayList<>();
for(Student s: list) {
if(s.getMath()>90) {
math90.add(s);
}
}
System.out.println("======集合过滤90分的:======");
for(Student s:math90) {
System.out.println(s.toString());
}
//流过滤90分的
List<Student> math90Stream = list.stream().filter(x -> x.getMath() > 90).collect(Collectors.toList());
System.out.println("======流过滤90分的:======");
math90Stream.forEach(System.out::println);
}
}
在demo中,我们先for循环构建了10条数据,输出结果如下:
======初始化数据:======
Student(classId=null, no=1, name=小明, age=12, math=85.0, chinese=null, english=null, score=null)
Student(classId=null, no=2, name=小华, age=12, math=86.0, chinese=null, english=null, score=null)
Student(classId=null, no=3, name=小志, age=12, math=87.0, chinese=null, english=null, score=null)
Student(classId=null, no=4, name=小东, age=12, math=88.0, chinese=null, english=null, score=null)
Student(classId=null, no=5, name=小李, age=12, math=89.0, chinese=null, english=null, score=null)
Student(classId=null, no=6, name=小张, age=13, math=90.0, chinese=null, english=null, score=null)
Student(classId=null, no=7, name=小王, age=13, math=91.0, chinese=null, english=null, score=null)
Student(classId=null, no=8, name=小周, age=13, math=92.0, chinese=null, english=null, score=null)
Student(classId=null, no=9, name=小吴, age=13, math=93.0, chinese=null, english=null, score=null)
Student(classId=null, no=10, name=小郑, age=13, math=94.0, chinese=null, english=null, score=null)
然后我们使用集合来遍历里面的数据,找到每个学生数学成绩大于90,并放入到结果集合中,输出结果如下:
======集合过滤90分的:======
Student(classId=null, no=7, name=小王, age=13, math=91.0, chinese=null, english=null, score=null)
Student(classId=null, no=8, name=小周, age=13, math=92.0, chinese=null, english=null, score=null)
Student(classId=null, no=9, name=小吴, age=13, math=93.0, chinese=null, english=null, score=null)
Student(classId=null, no=10, name=小郑, age=13, math=94.0, chinese=null, english=null, score=null)
最后我们使用了本节要将的流的处理方式,来过滤数学成绩岛屿90的学生集合,输出如下:
======流过滤90分的:======
Student(classId=null, no=7, name=小王, age=13, math=91.0, chinese=null, english=null, score=null)
Student(classId=null, no=8, name=小周, age=13, math=92.0, chinese=null, english=null, score=null)
Student(classId=null, no=9, name=小吴, age=13, math=93.0, chinese=null, english=null, score=null)
Student(classId=null, no=10, name=小郑, age=13, math=94.0, chinese=null, english=null, score=null)
其中要关注的代码:
List<Student> math90Stream = list.stream().filter(x -> x.getMath() > 90).collect(Collectors.toList());
list后跟这stream()方法,是将一个集合转换为流,后面又跟了一个filter()方法,其作用就是过滤,从这里我们可以看到流的遍历操作,并没有显示的循环代码,这就是我们上面提到的,流是内部迭代。
那么我们上面还提到了一个概念就是流是按需计算,也就是延时计算,只有真正用到的时候,计算才发生。
我们可以在上面的代码最后再添加一段代码:
//流的延时计算
Stream<Student> studentStream = list.stream().filter(x -> x.getMath() > 90);
List<Student> math90Stream2 = studentStream.collect(Collectors.toList());
System.out.println("======[演示计算]流过滤90分的:======");
math90Stream2.forEach(System.out::println);
你在运行的时候,可以在第二行的位置进行断点,执行时,你会发现第一行的studentStream对象,只是一个Stream对象,它的内部不存在我们需要的结果,那么这一行代码的作用仅仅是行为表达,还记得我们之前的章节说到的吗,Lambda的一个特性就是行为参数化,这里的第一行代码的作用就是表达的其行为,并没有实际产生任何结果数据,只有执行了第二行代码的collect(Collectors.toList())方法,才会进行过滤和计算,最终输出结果,这就是流的按需计算。
总结:Java中lambda的流,我们需要关注两个概念,一个是流是内部迭代,另一个是流的按需计算。