参考文献:
Java Stream中map和flatMap方法

map 方法

map 是一个中间操作,这意味着它返回 Stream 对象。

List<String> funs = Arrays.asList("F", "U", "N");
funs.stream().map(x -> x + "001").forEach(System.out::println);
F001
U001
N001

看个复杂点的

List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");

List<List<String>> nestedList = Arrays.asList(fun1, fun2);
nestedList.stream()
    .map(x -> x.stream().map(String::toUpperCase))
    .forEach(System.out::println);
java.util.stream.ReferencePipeline$3@7b23ec81
java.util.stream.ReferencePipeline$3@6acbcfc0

显然,在最后一步输出的时候,x 是一个 stream 的对象,而不是一个 list 对象。

当我们尝试从List<List<String>>获取值进行操作时,map 无法如预期一样工作,需要进行修改才能从嵌套的List<List<String>>对象获取字符串值。

List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");

List<List<String>> nestedList = Arrays.asList(fun1, fun2);
nestedList.stream().map(x -> x.stream().map(String::toUpperCase))
        .forEach(x -> x.forEach(System.out::println));
ONE
TWO
THREE
FOUR
FIVE
SIX

flatMap

让我们在上述代码中将 map 更改为 flatMap,然后查看输出。

List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");
List<List<String>> nestedList = Arrays.asList(fun1, fun2);
nestedList.stream().flatMap(Collection::stream)
        .map(String::toUpperCase)
        .forEach(System.out::println);
ONE
TWO
THREE
FOUR
FIVE
SIX

相当于在 .flatMap(x -> x.stream()) 这个时候我们把x.stream()返回的 stream 对象合并成了一个新的 stream 对象

区别

map 和 flatMap 方法都可以应用于 Stream<T>Optional<T> 对象。并且都返回Stream<R>Optional <U> 对象。区别在于 map 操作为每个输入值生成一个输出值,而 flatMap 操作为每个输入值生成任意数量(零个或多个)的输出值。

在 flatMap 中,每个输入始终是一个集合,可以是 List 或 Set 或 Map,扁平化处理,输出一个汇总值。

map 操作采用一个方法,该方法针对输入流中的每个值调用,并生成一个结果值,该结果值返回至stream。

flatMap 操作采用的功能在概念上消耗一个集合对象并产生任意数量的值。

List<String> fun1 = Arrays.asList("one", "two", "three");
List<String> fun2 = Arrays.asList("four", "five", "six");
Stream.of(fun1, fun2).flatMap(List::stream)
        .forEach(System.out::println);
one
two
three
four
five
six