流的操作分为两种:中间操作和终端操作。
中间操作:可以连起来的操作,中间操作会返回另一个流,除非流水线上触发一个终端操作,否则中间操作不会执行任何处理,因为中间操作一般都可以合并起来,在终端操作时一次性全部处理。
终端操作:关闭流的操作,终端操作会从流的流水线生成结果。生成的结果是任何不是流的值,比如List、Integer等。
我们以代码为例进行讲解,demo还是基于上一节的Student继续演示,上代码:
@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;
}
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class StreamTest2 {
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);
//流的流水线操作
System.out.println("======流的流水线操作:======");
List<String> std1 = list.stream().filter(x -> x.getMath() > 90d)
.map(Student::getName)
.limit(2)
.collect(Collectors.toList());
std1.forEach(System.out::println);
//流的中间操作详解,实际代码不推荐这样写
System.out.println("======流的中间操作详解:======");
List<String> std2 = list.stream().filter(x -> {
System.out.println("filter:"+x);
return x.getMath() > 90d;
})
.map(x-> {
System.out.println("map:"+x);
return x.getName();
})
.limit(2)
.collect(Collectors.toList());
}
}
第一部分还是新建了10条演示数据。
//流的流水线操作
System.out.println("======流的流水线操作:======");
List<String> std1 = list.stream().filter(x -> x.getMath() > 90d)
.map(Student::getName)
.limit(2)
.collect(Collectors.toList());
std1.forEach(System.out::println);
上面的第二行代码,除了最后的collect()方法,中间的filter()、map()、limit()方法,都是流的中间操作方法。collect()方法方法则是流的终端操作方法。
上面代码输出结果:
======流的流水线操作:======
小王
小周
输出了两条结果,因为使用了limit,作用就是取前两条。
我们将上面的代码继续改造一下,如下:
//流的中间操作详解,实际代码不推荐这样写
System.out.println("======流的中间操作详解:======");
List<String> std2 = list.stream().filter(x -> {
System.out.println("filter:"+x);
return x.getMath() > 90d;
})
.map(x-> {
System.out.println("map:"+x);
return x.getName();
})
.limit(2)
.collect(Collectors.toList());
这段代码同上一段代码的区别就是分别在filter方法和map方法中加入了一行System.out.println语句,用于打印方法执行时的内容,你会看到一些有趣的结果,输出如下:
======流的中间操作详解:======
filter:Student(classId=null, no=1, name=小明, age=12, math=85.0, chinese=null, english=null, score=null)
filter:Student(classId=null, no=2, name=小华, age=12, math=86.0, chinese=null, english=null, score=null)
filter:Student(classId=null, no=3, name=小志, age=12, math=87.0, chinese=null, english=null, score=null)
filter:Student(classId=null, no=4, name=小东, age=12, math=88.0, chinese=null, english=null, score=null)
filter:Student(classId=null, no=5, name=小李, age=12, math=89.0, chinese=null, english=null, score=null)
filter:Student(classId=null, no=6, name=小张, age=13, math=90.0, chinese=null, english=null, score=null)
filter:Student(classId=null, no=7, name=小王, age=13, math=91.0, chinese=null, english=null, score=null)
map:Student(classId=null, no=7, name=小王, age=13, math=91.0, chinese=null, english=null, score=null)
filter:Student(classId=null, no=8, name=小周, age=13, math=92.0, chinese=null, english=null, score=null)
map:Student(classId=null, no=8, name=小周, age=13, math=92.0, chinese=null, english=null, score=null)
我们分析一下打印结果,filter打印了8行,map打印了两行,而且最后的4行打印内容是filter和map相连打印的,从日志输出你就能推断出,filter和map被合并执行了,并不是我们认为的执行完全部filter,再执行map,而且最后的limit也是短路执行,发现满足2两数据,立刻停止继续执行,输出结果。
总结:流的操作包含一个数据源,一组流的中间操作和一个终端操作。