定义
流中的中间操作可以连接起来形成一个流水线,如果该流水线没有触发终止操作,那么中间操作是不会执行任何的处理的。只是会在终止条件中一次性全部执行,这个过程称为“惰性求值”。具体怎么理解,下面演示一个demo。首先有个概念stream中有个filter()为中间操作,也有一个方法forEach()属于终止操作。
demo的数据准备
编写一个实体类,主要用于创建对象然后放到集合中。Studen类中三个重写方法不一定需要覆盖的。
package com.mark.java8.entity;
public class Student {
String name ; //姓名
Integer age; //年龄
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
/**
*以下省略的get()和set()
**/
}
接下来看看测试类
public class StreamAPITest1 {
private List<Student> studentList = Arrays.asList(
new Student("Mark",23),
new Student("Eason",45),
new Student("Abel",18),
new Student("Jay",32),
new Student("Jack",50),
new Student("Jack",50));
//1.测试过滤API:filter()
@Test
public void testFilter() {
//1.获取流
//2.进行中间操作的filter方法
Stream<Student> studentStream = studentList.stream().filter((student)->{
System.out.println("中间操作"+student);
return student.getAge() > 18;
});
}
}
运行结果:并没有任何的输入语句,也就是filte方法中的输出语句没有执行到。因为测试方法中没有定义终止操作。接下来添加上终止的方法forEach()。
//1.测试过滤API:filter()
@Test
public void testFilter() {
//1.获取流
//2.进行中间操作的filter方法
Stream<Student> studentStream = studentList.stream().filter((student)->{
System.out.println("中间操作"+student);
return student.getAge() > 18;
});
//3.终止操作
studentStream.forEach(System.out::println);//使用内部迭代
}
运行结果:
中间操作Student{name=’Mark’, age=23}
Student{name=’Mark’, age=23}
中间操作Student{name=’Eason’, age=45}
Student{name=’Eason’, age=45}
中间操作Student{name=’Abel’, age=18}
中间操作Student{name=’Jay’, age=32}
Student{name=’Jay’, age=32}
中间操作Student{name=’Jack’, age=50}
Student{name=’Jack’, age=50}
中间操作Student{name=’Jack’, age=50}
Student{name=’Jack’, age=50}
2:中间操作
2.1:过滤操作:filter()
过滤操作的demo如上所示
2.2:限制操作:limit()
@Test
public void testLimit(){
studentList.stream()
.filter((student)->{//过滤操作返回年龄大于18的学生
System.out.println("filter--->"+student);
return student.getAge() > 18;
})
.limit(2)//中间操作限制返回2条结果
.forEach(System.out::println);//终止操作
}
输出结果:
filter—>Student{name=’Mark’, age=23}
Student{name=’Mark’, age=23}
filter—>Student{name=’Eason’, age=45}
Student{name=’Eason’, age=45}
总结:中间操作可以链式调用,limit()方法具有短路的属性,即找到满足条件后就不会继续往下执行了;如上面demo中的,找到两条满足条件的条件后就会继续往下执行了。
2.3:中间操作:跳过n个指定的元素:skip()
@Test
public void testSkip(){
studentList.stream().filter((student)->{
System.out.println("filter--->"+student);
return student.getAge() > 18;
}).skip(2)
.forEach(System.out::println);
}
运行结果:
filter—>Student{name=’Mark’, age=23}
filter—>Student{name=’Eason’, age=45}
filter—>Student{name=’Abel’, age=18}
filter—>Student{name=’Jay’, age=32}
Student{name=’Jay’, age=32}
filter—>Student{name=’Jack’, age=50}
Student{name=’Jack’, age=50}
filter—>Student{name=’Jack’, age=50}
Student{name=’Jack’, age=50}
运行结果分析:
学生Mark和Eason会被跳过,导致不会在终止操作中打印输出,
学生Abel不满足过滤条件大于18岁,导致不会在终止操作中打印输出,
剩下的几位运气不错都满足了过滤条件,所以他们都在终止操作中打印输出了。
总结:
skip()会返回的结果跳过指定的前n个元素,如果流中的元素不足n个,则返回的是一个空的流。
2.4:中间操作:筛选:skip()
该终止操作会过生成元素的hashCode()和equals()方法去除重复的元素
public void testDistinct(){
List<Student> studentList = Arrays.asList(
new Student("Mark",23),
new Student("Jack",50),//定义两个属性相同的对象
new Student("Jack",50));
studentList.stream().filter((student)->{//获取流然后执行中间操作过滤
System.out.println("filter--->"+student);
return student.getAge() > 18;
}).distinct() //通过筛选去除重复的元素
.forEach(System.out::println);//终止操作
}
运行结果:
filter—>Student{name=’Mark’, age=23}
Student{name=’Mark’, age=23}
filter—>Student{name=’Jack’, age=50}
Student{name=’Jack’, age=50}
filter—>Student{name=’Jack’, age=50}
运行结果分析:从打印语句中可以看出在终止操作中只是输出了一条学生Jack,注意(在学生Student实体类中我已经重写hashCode 和 equals 方法)