1准备数据
@Data
public class People {
private String name;
private Integer age;
private String sex;
public People(){ }
public People(String name,Integer age,String sex){
this.name = name;
this.age = age;
this.sex = sex;
}
public static List<People> listDemoPeople(){
List<People> list = new ArrayList<>();
list.add(new People("Jack",20,"boy"));
list.add(new People("Daniel",10,"boy"));
list.add(new People("Lucy",10,"girl"));
list.add(new People("Tom",40,"boy"));
list.add(new People("Nancy",30,"girl"));
return list;
}
}
2.filter()
@Test
public void test(){
List<People> list = People.listDemoPeople();
List<People> girls = list.stream().filter(p->p.getSex().equals("girl")).toList();
System.out.println(girls);
}
输出:
[People(name=Lucy, age=10, sex=girl), People(name=Nancy, age=30, sex=girl)]
注意:后面的.toList();返回是一个不可变list;
改成.collect(Collectors.toList());就是可变list;
List girls = list.stream().filter(p->p.getSex().equals("girl")).collect(Collectors.toList());
还有一点要注意,filter()里面写法是lambda表达式,写法简洁,但是要注意null,如果有的sex为null,就会报错。
List girls = list.stream().filter(p->p.getSex().equals("girl")).toList();
3.distinct()
distinct会用equals比较,Peope类需要重写equalst和hashCode两个方法,要保证equals为true时hashCode必须相等。我这里定义如果age相同,People就相同。
@Override
public boolean equals(Object p){
People o = (People) p;
if(this.age.equals(o.getAge())){
return true;
}else {
return false;
}
}
@Override
public int hashCode(){
return this.getAge();
}
@Test
public void distinct(){
List<People> list = People.listDemoPeople();
List<People> girls = list.stream().distinct().toList();
System.out.println(girls);
}
输出:结果中age各不相同
[People(name=Jack, age=20, sex=boy),
People(name=Daniel, age=10, sex=boy),
People(name=Tom, age=40, sex=boy),
People(name=Nancy, age=30, sex=girl)]
4.limit()和sorted
limit(n),输出n条数据,我这里输出一条
@Test
public void filter(){
List<People> list = People.listDemoPeople();
List<People> girls = list.stream()
.filter(p->p.getSex().equals("girl"))
.limit(1)
.toList();
System.out.println(girls);
}
输出:
[People(name=Lucy, age=10, sex=girl)]
注意limit(n), 如果stream中的数据是排好序的会输出前n条数据
public void filter(){
List<People> list = People.listDemoPeople();
List<People> girls = list.stream()
.sorted(Comparator.comparing(People::getAge))
.limit(3)
.toList();
System.out.println(girls);
}
输出:按age排序输出,从小到大:
[People(name=Daniel, age=10, sex=boy),
People(name=Lucy, age=10, sex=girl),
People(name=Jack, age=20, sex=boy)]
Comparator.comparing(People::getAge)默认从小到大排序,
加上.reversed()就是倒序,从大到小:
@Test
public void filter(){
List<People> list = People.listDemoPeople();
List<People> girls = list.stream()
.sorted(Comparator.comparing(People::getAge).reversed())
.limit(3)
.toList();
System.out.println(girls);
}
输出:
[People(name=Tom, age=40, sex=boy),
People(name=Nancy, age=30, sex=girl),
People(name=Jack, age=20, sex=boy)]
5.map和flatmap
姓名"Jack","Daniel","Lucy","Tom","Nancy"
现在要实现所有姓名中每个不同的字母只出输出一次
@Test
public void flatmap(){
List<People> list = People.listDemoPeople();
List<String[]> strs= list.stream()
.map(p->p.getName().split(""))
.distinct()
.toList();
for(String[] s:strs){
System.out.println(Arrays.toString(s));
}
}
输出:
[J, a, c, k]
[D, a, n, i, e, l]
[L, u, c, y]
[T, o, m]
[N, a, n, c, y]
.map(p->p.getName().split("")) 返回的是Stream(String[]), 就是{ [J, a, c, k], [D, a, n, i, e, l],[L, u, c, y], [T, o, m],[N, a, n, c, y]},一共5个姓名的数组。然后执行distinct()比较的是String[]数组,每个数组都不一样,所以输出全部数组。
我们想要的是5个姓名组成一个大的数组{ J, a, c, k, D, a, n, i, e, l,L, u, c, y, T, o, m,N, a, n, c, y},然后对这个数组执行distinct(),比较的就是每个字母,最终输出不同的字母。
可以用flatMap,代码如下:
可以看代码中map和flatMap后面的提示,map后流中是String数组(就是上面5个姓名的数组),flatMap后流中是一个个String(就是5个姓名所有的字符)
@Test
public void flatmap(){
List<People> list = People.listDemoPeople();
List<String> strs = list.stream()
.map(p->p.getName().split(""))
.flatMap(s-> Arrays.stream(s))
.distinct()
.toList();
System.out.println(strs);
}
输出是:
[J, a, c, k, D, n, i, e, l, L, u, y, T, o, m, N]
6.查询匹配方法
allMatch、anyMatch、noneMatch、findFirst,findAny这些方法,看名称就知道意思了,就不一一介绍,以allMatch为例:查询所有人的age是否都小于100。
@Test
public void allMatch(){
List<People> list = People.listDemoPeople();
boolean b = list.stream().allMatch(p-> p.getAge() < 100);
System.out.println(b);
}
输出:
true
7.reduce
reduce()有两种写法,
- 一种有初始值,reduce(初始值,函数式接口)
- 一种没有初始值,reduce(函数式接口)
函数式接口要求是:传入两个同类型对象a和b,经过一系列计算,返回的一个对象(这个对象的数据类型要和a,b类型一样)
reduce如果有初始值,初始值的类型也要和a,b类型一样。
简单来说,reduce就是把流中的数据进行两两计算。
下面用reduce这两种方法,实现求所有人的age和
写法1:.reduce(0,(a,b)->a+b);
reduce第一个参数是0,就是初始值,如果所有人的age都为null的话,和就是0
@Test
public void reduce(){
List<People> list = People.listDemoPeople();
Integer sum = list.stream().map(p->p.getAge())
.reduce(0,(a,b)->a+b); //这里0,a,b ,a+b都是int,同一类型。
System.out.println(sum);
}
输出:
110
写法2:.reduce((a,b)->a+b);没有初始值,如果所有人的age都为null的话,就没有和,所以返回的是Optional<>
@Test
public void reduce(){
List<People> list = People.listDemoPeople();
Optional<Integer> sum = list.stream().map(p->p.getAge())
.reduce((a,b)->a+b);
System.out.println(sum.get());
}
输出:
110
求最大age的人
@Test
public void reduce(){
List<People> list = People.listDemoPeople();
Optional<People> p = list.stream()
.reduce((a,b)-> { //这里a,b,和下面return都是People类型
if(a.getAge() - b.getAge() > 0){
return a;
}else {
return b;
}
});
System.out.println(p.get());
}
输出:
People(name=Tom, age=40, sex=boy)
8.Collectors.groupingBy
把相同age的人放在一起
@Test
public void groupBy(){
List<People> list = People.listDemoPeople();
Map<Integer, List<People>> map = list.stream()
.collect(Collectors.groupingBy(People::getAge));
System.out.println(map);
}
输出:
{20=[People(name=Jack, age=20, sex=boy)],
40=[People(name=Tom, age=40, sex=boy)],
10=[People(name=Daniel, age=10, sex=boy), People(name=Lucy, age=10, sex=girl)],
30=[People(name=Nancy, age=30, sex=girl)]}
9.Collectors.toMap
@Test
public void toMap(){
List<People> list = People.listDemoPeople();
Map<Integer, People> map = list.stream()
.collect(Collectors.toMap(People::getAge,p->p,(oldValue, newValue) -> newValue));
System.out.println(map);
}
输出:
{20=People(name=Jack, age=20, sex=boy),
40=People(name=Tom, age=40, sex=boy),
10=People(name=Lucy, age=10, sex=girl),
30=People(name=Nancy, age=30, sex=girl)}
Collectors.toMap(People::getAge,p->p,(oldValue, newValue) -> newValue),含义如下:
- People::getAge,用age作为key
- p->p, 用People作为value
- (oldValue, newValue) -> newValue,如果key相同(有相同的age),value用新的people替换原来的people
如果我们确定所有人的age都不一样,不会有冲突可以这样写
Collectors.toMap(People::getAge,p->p)
10.Collectors.partitioningBy
按sex分区,两个key是true和false
@Test
public void partitioningBy(){
List<People> list = People.listDemoPeople();
Map<Boolean, List<People>> map = list.stream()
.collect(Collectors.partitioningBy(p->p.getSex().equals("boy")));
System.out.println(map);
}
输出:
{false=[People(name=Lucy, age=10, sex=girl), People(name=Nancy, age=30, sex=girl)],
true=[People(name=Jack, age=20, sex=boy), People(name=Daniel, age=10, sex=boy), People(name=Tom, age=40, sex=boy)]}
求不同sex中age最大的人
@Test
public void partitioningBy(){
List<People> list = People.listDemoPeople();
Map<Boolean, People> map = list.stream()
.collect(Collectors.partitioningBy(p->p.getSex().equals("boy"),
Collectors.collectingAndThen(
Collectors.maxBy((a,b)-> a.getAge()-b.getAge()),
p-> p.get()))
);
System.out.println(map);
}
输出:
{false=People(name=Nancy, age=30, sex=girl),
true=People(name=Tom, age=40, sex=boy)}