一、Stream简介
Stream是一个数据流通道,用来操作集合、数组、数据源中的序列,并生成新的集合序列,在数据流通道中会对原来的集合、数组、数据源中的序列进行计算,计算的结果会生成一个新的序列,放在一个新的源中。
运用Stream操作分三步:创建Stream流、流中间操作、终止流操作
注意:
1. Stream本省不会存储元素;
2. Stream不会改变原来源对象,相反,会返回一个持有结果的新Stream;
3. Stream操作是延迟执行的,这意味着需要数据流通道的计算结果时才执行。
从创建数据源到终止数据源操作,中间会经过一系列的流操作,如下图所示
下面演示中间通道流操作的筛选与切片功能
二、筛选与切片
首先创建一个list集合,作为old数据源。
public static List<User> users = Arrays.asList(
new User("lzj", 25),
new User("zhangsan", 26),
new User("lisi", 30),
new User("wanger", 18),
new User("zhaowu", 29),
new User("zhaowu", 29));
1、filter从通道流中按自定义的规则过滤出满足条件的序列
原数据源中放置了7个User类型的对象,现在需要在通道流中过滤出年龄大于20的对象。
@Test
public void test(){
Stream<User> stream = users.stream() //创建通道流
.filter((x) -> { //过滤通道流
Boolean flag = x.getAge() > 20;
return flag;
});
/*方法一:*/
// Consumer<User> consumer = (t) -> System.out.println(t);
// stream.forEach(consumer);
// System.out.println("==============================");
/*方法二:*/
stream.forEach(System.out::println); //终止通道流
/*方法三:三种方式都是Lambda的变形体*/
/*stream只执行一遍,就会关闭*/
// System.out.println("------------------------------");
// stream.forEach((t) -> {System.out.println(t);});
}
filter过滤方法中传入的参数是Predicate函数式接口类型的对象,通过自定义Predicate接口中的test方法体来判断过滤出符合条件的对象,test方法返回true的对象会被过滤出来。
forEach用来终止流,forEach方法中传入的Consumer函数式接口实现的对象,需要实现接口中的 void accept(T t)方法,forEach会对流中的每个元素执行acctpt方法,本案例中是对每个元素进行输出。
运行方法,输出结果如下:
User [name=lzj, age=25]
User [name=zhangsan, age=26]
User [name=lisi, age=30]
User [name=zhaowu, age=29]
User [name=zhaowu, age=29]
2、截断流,使流中元素不超过指定数量
使用limit可以截取流中指定数量的元素序列。
@Test
public void test1(){
users.stream() /*创建流*/
.filter((x) -> x.getAge() >= 20) /*过滤出满足条件的流*/
.limit(3) /*只截取流中满足条件的前3个序列*/
.forEach(System.out::println); /*终止流*/
}
运行测试方法,输出内容如下:
User [name=lzj, age=25]
User [name=zhangsan, age=26]
User [name=lisi, age=30]
从输出结果中可以看出,只输出了流中满足条件的前3个。
3、skip跳过流中指定个数的序列
用skip(n)可以跳过流中的元素,返回一个扔掉了前n个元素的流。若流中的元素不满足n个,则返回一个空流。与limit(n)互补。
@Test
public void test2(){
users.stream() /*创建流*/
.filter((x) -> x.getAge() >= 20) /*过滤流*/
.skip(2) /*跳过流*/
.forEach(System.out::println); /*终止流*/
}
运行测试方法,输出结果:
User [name=lisi, age=30]
User [name=zhaowu, age=29]
User [name=zhaowu, age=29]
4、distinct去除流中重复元素
通过流中元素的hashCode()和equals()方法去除流中重复的元素。
首先重写User类中hashCode和equals方法
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/*自动生成hashCode方法*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
/*自动生成equals方法*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
下面重新创建old数据源
public static User user1 = new User("lzj", 20);
public static User user2 = new User("zhangsan", 30);
public static List<User> users2 = Arrays.asList(user1,user1,user2);
下面用distinct去除流中重复的元素
@Test
public void tst3(){
users2.stream()
.distinct()
.forEach(System.out::println);
}
运行测试方法,输出结果如下:
User [name=lzj, age=20]
User [name=zhangsan, age=30]