可以这么说,Stream流几乎可以完成对集合的任意操作,过滤、限流、跳过、映射、排序、分组等
下面讲一下其中比较难理解的两个映射操作map和flatMap的区别
推荐直接从源码开始看:
-
map源码
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
参数:传入一个Function函数式接口,类型分别是T、R
返回:Stream流,类型是R
作用:将T类型经过某种映射(由函数式接口抽象方法实现决定),变成R类型的Stream流 -
flatMap源码
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
参数:传入一个Function函数式接口,类型T、 Stream< R >
返回:Stream流,类型是R
作用:将T类型经过某种映射(由函数式接口抽象方法实现决定)(原本要转成 Stream< Stream< R > >),变成R类型的Stream流
看源码应该就能看出来区别了吧
map函数式接口抽象方法的返回值是R,flatMap函数式接口抽象方法返回值是Stream< R >
所以flatMap作用就是将返回的Stream< R >拆开,再组合每个值成新的Stream< R >
示例:
@Test
public void test2() {
Student[] students = new Student[] { new Student("a.a", 1), new Student("b.b", 2),
new Student("c.c", 3), new Student("d.d", 4), new Student("e.e", 5) };
// Stream流中间操作---映射map
Arrays.asList(students).stream().map(Student::getName).forEach(System.out::println);
System.out.println("*********************************");
// 比较区别,map(s->s.split("\\."))收集之后的结果是Stream<String[]>
Arrays.asList(students).stream().map(Student::getName).map(s->s.split("\\.")).forEach(arr-> System.out.println(Arrays.toString(arr)));
System.out.println("*********************************");
// Stream流中间操作---扁平化映射flatmap,看源码可以发现,Function函数式接口的第二个参数是Stream<? extends R>
// 也即,lambda表达式的返回值是Stream<? extends R>类型
// 那作用也就显而易见了,把每个返回值的Stream,再一个个拆开,最后综合所有的变成一个新的Stream
Arrays.asList(students).stream().map(Student::getName).flatMap(s->Arrays.stream(s.split("\\."))).forEach(System.out::println);
}
map(s->s.split("\."))收集之后的结果是Stream<String[]>
打印结果:
a.a
b.b
c.c
d.d
e.e
*********************************
[a, a]
[b, b]
[c, c]
[d, d]
[e, e]
*********************************
a
a
b
b
c
c
d
d
e
e
其实就类似于集合里面的put和putAll的区别
putAll将集合拆开再一个个加进另一个集合
put就是直接加进集合
以上是自己学习过程的理解,如有不妥,谢谢指正~