君子成人之美,不成人之恶。小人反是。——《论语》
在Stream
中有这么一个函数
它和map
不一样的是,map
你输入多少个,输出就是多少个
例如我要生成一个集合,装着26
个小写字母和26
个大写字母
用flatMap
可以一行实现
1 | List<String> abc = Stream.iterate('a', i -> ++i).map(String::valueOf).limit(26).flatMap(i -> Stream.concat(Stream.of(i), Stream.of(i).map(String::toUpperCase))).sorted().collect(Collectors.toList()); |
马上这时候就有人跳出来说,我不用flatMap
还不是可以!!!不信你看
1 | List<Character> ab = Stream.iterate('A', i -> ++i).limit(58).filter(i -> i < 91 || i > 96).collect(Collectors.toList()); |
。。。我只能说,我这篇博客是写flatMap
,所以不要杠,我知道Stream.concat
可以换成Stream.of
而且,你下面这种方式生成58
个元素,其中浪费了6
个元素
而我上面的方式只用26
个元素就生成了54
个元素
哪种方式的入参代价更小,明白了吧
那么这个flatMap
如何使用?
再来看个例子:
九九乘法表都会吧
我们用flatMap
一行写一个
1 | List<String> nineNine = Stream.iterate(1, i -> ++i).flatMap(i -> Stream.iterate(i, in -> ++in).map(in -> i + "*" + in + "=" + i * in).limit(10 - i)).limit(45).collect(Collectors.toList()); |
看懂了吗?
还看不懂???
那我们来读源码
1 | <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper); |
可以看到flatMap
里就一个参数,Function
而关键就在于Function
的两个泛型,注意不是T
和R
,而是? super T
和? extends Stream<? extends R>
然后现在你可能有点懵,这两个泛型干嘛的
第一个泛型? super T
你甚至可以忽略掉? super
去看,直接把他认为是泛型T
,而这个泛型T
,就是我们原来的元素
简单来说,它就是你的入参,就是你的集合里的每一个元素
就是.flatMap(i -> Stream.concat(Stream.of(i), Stream.of(i).map(String::toUpperCase)))
中的i
第二个泛型? extends Stream<? extends R>
同理,你先忽略掉? extends
,表示你的返回值需要Stream<R>
类型
这个R
可以和T
一样,也可以不一样
例如我这里就是一样的,都是String
类型,我使用Steam.of
以及Stream.concat
函数去将我们的元素转换成Stream
再返回
就是.flatMap(i -> Stream.concat(Stream.of(i), Stream.of(i).map(String::toUpperCase)))
中箭头右边部分
举个开发中遇到的场景
假设用户类,其中部分用户有个父账户id
,对应父账户,使用的同一张表
你现在拿到了一个包含这些用户的list
,需要把用户id
和父账户id
放到一个list
里面去进行in
查询
就可以这么写
1 | List<User> userList = new ArrayList<>(); |
打印出来结果
Optional
中也有flatMap
函数,这个我们之后再讲