基于前面讲的创建Stream流和Stream的中间方法,今天我们来说Stream流的终结方法,终结方法主要有以下四个:遍历、统计、收集(收集流中的数据,存放到数组中)、收集(收集流中的数据,存放到集合中)
首先就是遍历(forEach)
依次获取流里面的数据
我们看forEach的底层代码,可以发现其实forEach底层就是个函数式接口,所以我们要将其改成lambda表达式
函数式接口的具体内容可以参考函数式接口
代码如下
package com.itheima;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
public class StreamDemo9 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰","张翠山","张良","王二麻子","谢光坤");
//遍历 void foreach(Consumer action)
//consumer的泛型:表示流中数据的类型
//accept方法的形参s:表示流里面的每一个数据
//方法体:对每一个数据的处理操作(打印)
list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
}
}
我们将其改成lambda表达式
图中我们可以发现forEach的返回值为void,这表明forEach方法结束后,不能在调用流里面的其他方法(就是后面不能再加“点”什么了),即终结方法
list.stream().forEach(s -> System.out.println(s));
统计(count)
我们可以发现,count类型的返回值是一个long类型的整数,所以同上,他也不能在调用流里面的其他方法了,即中介方法
long count = list.stream().count();
System.out.println(count);
收集(toArray())
收集流中数据,放到数组中
我们可以发现,toArray有两种,观察其返回类型,我们需要具体的类型,所以调用下面的那个方法
//toArray() 收集流中数据,放到数组中
//IntFunction的泛型:具体类型的数组
//apply的形参:流中数据的个数,要跟数组恶长度保持一致
//apply的返回值:具体类型的数组
//方法体:创建数组
//toArray方法的参数的作用:负责创建一个指定类型的数组
//toArray方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中
//toArray方法的返回值:是一个装着流里面所有数据的数组
String[] arr = list.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
System.out.println(Arrays.toString(arr));
将其改成lambda表达式
String[] arr2 = list.stream().toArray((value) -> new String[value]);
System.out.println(Arrays.toString(arr2));
收集集合(collect)
收集流中的数据,放到集合中(List,Set,Map)
首先,我们收集到list集合中
package com.itheima;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class StreamDemo10 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌-男-15", "周芷若-女-14", "赵敏-女-13", "张强-男-20", "张三丰-男-100", "张翠山-男-40", "张良-男-35", "王二麻子-男-37", "谢光坤-男-41");
//收集list集合当中
//需求:把所有的男性收集起来
List<String> newList = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toList());
System.out.println(newList);
}
}
第二种,收集到set集合中
//收集set集合当中
//需求:把所有的男性收集起来
//.collect(Collectors.toSet());会在底层创建一个hashset的集合,并把流里面的数据放到set集合当中
Set<String> newList2 = list.stream().filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toSet());
System.out.println(newList2);
区别:收集到list不会去重
hashset会把重复值去掉
第三种,收集到map集合中
调用map方法,需要设置其键和值
我们观察底层代码,找到键和值的约定规则
我们按照上述规则对代码进行编写(注释中有对应的解释)
//收集set集合当中
//需求:把所有的男性收集起来
//.collect(Collectors.toSet());会在底层创建一个hashset的集合,并把流里面的数据放到set集合当中
Set<String> newList2 = list.stream().filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toSet());
System.out.println(newList2);
//收集map集合当中
//谁作为键,谁作为值
// 需求:把所有的男性收集起来 键:姓名 值:年龄 //
// new Function中第一个泛型表示流里面的数据类型,第二个泛型表示MAP集合当中键(姓名)的类型
Map<String, Integer> map = list.stream().filter(s -> "男".equals(s.split("-")[1]))
/*
* toMap : 参数1表示键的生成规则
* 参数2表示值的生成规则
* 参数一:
* Function:泛型1:表示流中每一个数据的类型
* 泛型2:表示Map集合中键的数据类型
*
* 方法apply形参:依次表示流里面的每一个数据
* 方法体:生成键的代码
* 返回值:已经生成的键(string、integer)
* */
.collect(Collectors.toMap(new Function<String, String>() {
@Override
public String apply(String s) {
//张无忌-男-15
return s.split("-")[0];
}
},
new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s.split("-")[2]);
}
}));
System.out.println(map);
需要注意的是:如果我们要收集到Map集合当中,map中的键不能重复,否则会报错!
至于为什么会这样,我们可以简单查看一下toMap的源码
底层封装了putIfAbsent这样一个方法,具体解释是:根据键先找值,如果值为null,表示当前键为空的,是不存在的,这是就可以把数据添加到map集合中,但是如果重复,进行第二次添加的时候v就不是null了
如果不为null,就会产生一个异常
上面是我们用匿名内部类写的toMap方法
最后我们要将其写成lambda表达式
Map<String, Integer> map2 = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toMap(
s -> s.split("-")[0],
s -> Integer.parseInt(s.split("-")[2])
));
System.out.println(map2);
以上就是我们stream流的所有终结方法了,结合前面我们总结一下stream流
1.Stream流的作用
结合Lambda表达式,简化集合、数组的操作
2.Stream流的使用步骤
- 获取Stream流对象
- 使用中间方法处理数据
- 使用终结方法处理数据
3.如何获取Stream流对象
- 单列集合:Collection中的默认方法stream
- 双列集合:不能直接获取
- 数组:Arrays工具类型中的静态方法stream
- 一堆零散的数据:Stream接口中的静态方法of
4.常见方法
中间方法:filter,limit,skip,distinct,concat,map
终结方法:forEach,count,collect(set,list,map)