Java Stream中map和flatMap方法

时间:2022-07-27
本文章向大家介绍Java Stream中map和flatMap方法,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

最近看到一篇讲stream语法的文章,学习Javamap()flatMap()方法之间的区别。

虽然看起来这两种方法都做同样的事情,都是做的映射操作,但实际上差之毫厘谬以千里。

通过演示Demo中的代码可以了解map()flatMap()的具体功能差异。

  • 首先来一段简单的stream语法foreach方法的用法

演示Demo:

        List<String> funs = Arrays.asList("F", "U", "N");
        funs.stream().forEach(x -> output(x));

控制台输出:

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
F
U
N

Process finished with exit code 0

map方法

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

  • 先来一个简单

演示Demo:

        List<String> funs = Arrays.asList("F", "U", "N");
        funs.stream().map(x->x+"001").forEach(x->output(x));

控制台输出:

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
INFO-> f
INFO-> u
INFO-> n
INFO-> F001
INFO-> U001
INFO-> N001
java.util.stream.ReferencePipeline$3@27ae2fd0
java.util.stream.ReferencePipeline$3@29176cc1

Process finished with exit code 0

  • 再来一个复杂的

演示Demo:

        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 -> {
            return x.stream().map(a -> a.toUpperCase());
        }).forEach(x -> output(x));
        

控制台输出:

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
INFO-> java.util.stream.ReferencePipeline$3@45018215
INFO-> java.util.stream.ReferencePipeline$3@30b7c004

显然,在最后一步输出的时候,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 -> {
            return x.stream().map(a -> a.toUpperCase());
        }).forEach(x ->x.forEach(a->output(a)));

控制台输出:

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
INFO-> ONE
INFO-> TWO
INFO-> THREE
INFO-> FOUR
INFO-> FIVE
INFO-> SIX

Process finished with exit code 0

flatMap方法

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

  • 先来一个简单

演示Demo:

        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(x -> x.stream()).map(x->x.toUpperCase()).forEach(x -> output(x));

控制台输出:

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
INFO-> ONE
INFO-> TWO
INFO-> THREE
INFO-> FOUR
INFO-> FIVE
INFO-> SIX

Process finished with exit code 0

相当于在.flatMap(x -> x.stream())这个时候我们把x.stream()返回的stream对象合并成了一个新的stream对象。这一点在Stream类的方法注释中找到了印证。

  /**
  ·····
     * @return the new stream
     */
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

Java 8 map()与flatMap()

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

flatMap()中,每个输入始终是一个集合,可以是ListSetMap

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

flatMap()操作采用的功能在概念上消耗一个集合对象并产生任意数量的值。但是在Java中方法返回任意数目的值很麻烦,因为方法只能返回void或一个对象。

演示Demo:

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

控制台输出:

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
INFO-> one
INFO-> two
INFO-> three
INFO-> four
INFO-> five
INFO-> six

Process finished with exit code 0