美文网首页
用Java DIY 函数式方法—— flatmap

用Java DIY 函数式方法—— flatmap

作者: 檀木丁 | 来源:发表于2017-03-14 13:49 被阅读486次

    本文是 用Java DIY 函数式方法—— map 续篇, 解决如何使用java实现函数式方法-flatmap。

    注意

    • 不适合对函数式一点基础都没有的读者
    • DIY实现不是完美的,仅仅是用实例表达函数式方法的理解
    • 这个系列文章不是分析java 8 stream中的方法源码,而是对java 8 stream特性,结合Kotlin, Rxjava之类的理解, 使用纯java的方式实现类似的函数式方法。
    • 需要对java 中的泛型以及Collection有了解
    • 会用到java 8 lambda表达式
    • 要实际代码验证,需要 jdk 1.8

    讲解的模式如下:

    • 给出某个场景
    • 使用 java 8
    • 使用DIY 函数实现

    那就进入主题吧: 用Java DIY 函数式方法——flatmap

    DIY 函数式方法flatmap

    作用: T -> Collection<R> 注意,这是DIY实现理解,Kotlin,java 8 stream各有自己的集合表达

    /** 需求:
    * 给定 1 个 Integer集合[1,2,3,4,5]
    * 将该集合转换为String类型集合["1a", "1b", "2a", "2b", "3a", "3b", "4a","4b", "5a", "5b"]
    * 思路: [1,2,3,4,5] -> ["1a", "1b"], ["2a", "2b"], ["3a", "3b"], ["4a","4b"], ["5a", "5b"]
    * -> ["1a", "1b", "2a", "2b", "3a", "3b", "4a","4b", "5a", "5b"]
    */
    

    分析: map能解决的是 T -> R的变化, 上述需求有点特别,需要将 [1, 2, 3, 4, 5] 其中的每一个都要添加 "a", "b", 然后把他们整合成一个集合。
    要是只能使用map实现,也可以, 可行思路是, 如有好的map思路,请留言!!!

    • [1,2,3,4,5] -> ["1a", "2a", "3a", "4a", "5a"]
    • [1,2,3,4,5] -> ["1b", "2b", "3b", "4b", "5b"]
    • 手动合并,还需要排序达到 ["1a", "1b", "2a", "2b", "3a", "3b", "4a","4b", "5a", "5b"]

    1. java 8 stream实现

    List<Integer> integerList = Arrays.asList(1,2,3,4,5);
    integerList.stream()
                    .flatMap(new Function<Integer, Stream<String>>() {
                        @Override
                        public Stream<String> apply(Integer integer) {
                            return Arrays.asList(integer + "a", integer + "b").stream();
                        }
                    }).forEach( item -> out.print(item + " ") );
    

    说明: 上述一条链式调用,就解决了我们的需求

    lamdba表达式,简洁如下:

    integerList.stream()
      .flatMap(integer -> Arrays.asList(integer + "a", integer + "b").stream())
      .forEach(item -> out.print(item + " ") );
    

    2. DIY flatmap

    在DIY 之前,需要梳理 flatmap的 核心是什么?

    T -> Collection<R>

    注意:这是DIY flatmap基于Collection实现,Kotlin, java 8 stream各有自己的转换关系!

    所以,需要三个东西: 输入 T, 输出 Collection<R>, 映射关系!

    public static <T, R> Collection<? super R> flatMap(Collection<? extends T> collection,
                                                    Function<T, Collection<R>> function) {
            Collection<? super R> result = new ArrayList<>();//这里仅仅是演示
            for(T item: collection){
                result.addAll(function.call(item));
            }
            return result;
        }
    
        public interface Function<T, R>{
            R call(T item);//T -> R
        }    
    

    其中: Collection<? super R> 是flatmap返回值类型, Collection<? extends T> 是输入参数的类型
    Function<T, Collection<R>> function 是映射关系, T -> Collection<R>

    //这里仅仅是演示
    Collection<? super R> result = new ArrayList<>();
    

    一直强调 DIY的实现是有局限性的,我这里是在java集合的基础上,而且选用ArrayList作为实际的主体,要是其他数据结构类型,肯定就没法使用, 但是,不影响 讲解flatmap实现的思路!

    如上, 使用者,只需要关注 Function 接口的具体实现方法call的设计。

    使用方式如下:

    List<Integer> integerList = Arrays.asList(1,2,3,4,5);
    
    flatMap(integerList, new Function<Integer, Collection<String>>() {
        @Override
        public Collection<String> call(Integer item) {
            return Arrays.asList(item + "a", item + "b");
        }
    }).forEach(item -> out.print(item + " ") );
    

    lambda简化:

    flatMap(integerList, integer -> Arrays.asList(integer + "a", integer + "b") )
                    .forEach(item -> out.print(item + " "));
    

    其他实例:将三个IntegerList整合为一个List [1], [2,3], [4,5,6] -> [1,2,3,4,5,6]

    Collection<List<Integer>> input = Arrays.asList(
                    Arrays.asList(1),
                    Arrays.asList(2,3),
                    Arrays.asList(4, 5, 6));
    
            flatMap(input, item -> new ArrayList<Integer>(item))
                    .forEach(out::println);
    

    小结

    理解 T -> Collection<R>,就明白了flatmap的原理了,遇到实际的情况,可以考虑用flatmap实现,体会跟传统的不同之处!
    代码上传到 csdn 资源下载

    喜欢,用实际点赞支持我吧! 欢迎留言讨论!

    相关文章

      网友评论

          本文标题:用Java DIY 函数式方法—— flatmap

          本文链接:https://www.haomeiwen.com/subject/auwcnttx.html