What is flatMap()?
# Stream<String[]>
# Stream<Stream<String>>
# String[][][[1, 2],[3, 4],[5, 6]
]
它由一个 2 级 Stream
或一个二维数组组成 。
在 Java 8 中,我们可以使用 flatMap
将上述 2 级 Stream
转换为一级 Stream
或将 二维数组转换为 一维数组。
# Stream<String>
# String[][1, 2, 3, 4, 5, 6]
简言之, flatmap
方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接
起来成为一个流。
看一个简单的例子: 使用flatMap
找出单词列表中各不相同的字符
Why flat a Stream?
处理包含多个级别的 Stream ,比如 Stream<String[]>
或 Stream<List<LineItem>>
或 Stream<Stream<String>>
想 将 2 级 Stream 扁平化为一级,如 Stream<String>
或 Stream<LineItem>
,这样就可以轻松地循环 Stream 并对其进行处理。
来看个简单的功能实现,以及常犯的一些错误。
需求: 有 {"a", "b"}, {"c", "d"}, {"e", "f"}
三个数组,要求输出 除去a
之后的数据
/*** filter out the a and print out all the characters*/private static void filterAndPrintCharacters() {String[][] array = new String[][]{{"a", "b"}, {"c", "d"}, {"e", "f"}};// convert array to a streamStream<String[]> stream = Arrays.stream(array);// array to a stream [same result]Stream<String[]> array1 = Stream.of(array);log.info("==========错误的方式一===============");// x is a String[], not String!List<String[]> result = stream.filter(x -> !x.equals("a")).collect(Collectors.toList());log.info(String.valueOf(result.size()));result.forEach(x -> log.info(Arrays.toString(x)));log.info("==========错误的方式二===============");List<String[]> result1 = Arrays.stream(array).filter(x -> {for (String s : x) { // really?if (s.equals("a")) {return false;}}return true;}).collect(Collectors.toList());log.info(String.valueOf(result1.size()));result1.forEach(x -> log.info(Arrays.toString(x)));log.info("============正确的方式 flatMap=============");log.info("============先测试转换成一维数组=============");// [a, b, c, d, e, f]String[] objects = Arrays.stream(array).flatMap(Stream::of).toArray(String[]::new);Arrays.stream(objects).forEach(x -> log.info("|---->{}", x));log.info("============开始处理=============");List<String> collect = Arrays.stream(array).flatMap(Stream::of).filter(x -> !x.equals("a")).collect(Collectors.toList());collect.forEach(x -> log.info(x));log.info("============处理结束=============");}
我们先看看:
[错误的方式一]
filter(x -> !x.equals("a")) // x 是数组 ,而非字符串
[错误的方式二]
x -> {for (String s : x) { // really?if (s.equals("a")) {return false;}}return true;} // 会把整个 [a, b] 过滤出去,而非我们想要过滤的 a
[正确的方式 ]
// flatMap 将二维数组转换成意味数组, 或者可以说是从 Stream<String[]> 转换成Stream<String>.String[][] array = new String[][]{{"a", "b"}, {"c", "d"}, {"e", "f"}};// Java 8String[] result = Stream.of(array) // Stream<String[]>.flatMap(Stream::of) // Stream<String>.toArray(String[]::new); // [a, b, c, d, e, f]Arrays.stream(objects).forEach(x -> log.info("|---->{}", x));
接下来我们就可以很轻松地过滤出来 a了, 就得到了一下最终版本
List<String> collect = Arrays.stream(array).flatMap(Stream::of).filter(x -> !x.equals("a")).collect(Collectors.toList());collect.forEach(x -> log.info(x));
【小结】
Stream#flatMap
可以将 2 levels Stream 转换成 1 level Stream.
Stream<String[]> -> flatMap -> Stream<String>
Stream<Set<String>> -> flatMap -> Stream<String>
Stream<List<String>> -> flatMap -> Stream<String>
Stream<List<Object>> -> flatMap -> Stream<Object>
Demo
需求: 使用 stream
将List转换为对象流,每个对象都包含一组书籍,使用flatMap
生成包含所有对象中所有书籍的流。过滤掉包含单词python的书,并收集一个Set以删除重复的书。