Stream->flatMap (扁平化处理)
场景一
有这样一个结构:
[ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
想将其转换成这样的结构:
[ 1, 2, 3, 4, 5, 6 ]
怎么实现?
数据准备:
public class FlatMapTest {
public static final List<List<Integer>> LIST = new ArrayList<>();
static{
LIST.add(Arrays.asList(1,2,3));
LIST.add(Arrays.asList(4,5,6));
}
}
方案一:for循环
@Test
public void test1(){
Set<Integer> flatMapSet = new HashSet<>();
LIST.forEach(flatMapSet::addAll);
flatMapSet.forEach(System.out::println);
}
方案二:flatMap
@Test
public void test2() {
Set<Integer> flatMapSet = LIST.stream().flatMap(Collection::stream).collect(Collectors.toSet());
flatMapSet.forEach(System.out::println);
}
小结:
除了for循环,java8的Stream还专门提供了“扁平化”处理集合的API
for循环 VS flatMap
在场景一下,代码实现上从代码的优雅简洁程度上来看,二者差不多。如果稍微复杂一点呢?比如现在想把1给过滤掉。
方案一:for循环
@Test
public void test11(){
Set<Integer> flatMapSet = new HashSet<>();
LIST.forEach(l->{
for (Integer integer : l) {
if (integer != 1){
flatMapSet.add(integer);
}
}
});
flatMapSet.forEach(System.out::println);
}
方案二:flatMap
@Test
public void test22() {
Set<Integer> flatMapSet = LIST.stream()
.flatMap(Collection::stream)
.filter(f -> f != 1)
.collect(Collectors.toSet());
flatMapSet.forEach(System.out::println);
}
对比
增加了一点点复杂度之后,显然使用flatMap更优雅
结论
遇到这种需扁平化处理集合元素的场景下,直接选择使用flatMap,不要使用for循环,1来是for循环不够优雅,2是for循环可扩展性很差
flatMap参数解析
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
参数是一个Function,Function的出参是一个Stream,也就是说需要提供一个可以将元素转换成Stream的方法
比如:
java.util.Collection#stream
java.util.stream.Stream#of(T)
其它案例场景
@Test
public void test3() {
// 将所有字符串按"-"分割然后放到一个大集合中
List<String> list = Arrays.asList("AB-CD", "AB-EF-GH", "IG-KL");
Set<String> flatMapSet = list.stream()
.flatMap(f -> {
String[] arr = f.split("-");
return Stream.of(arr);
})
.collect(Collectors.toSet());
flatMapSet.forEach(System.out::println);
}