1. 程式人生 > >用Java DIY 函式式方法—— flatmap

用Java DIY 函式式方法—— flatmap

本文是 用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 資源下載



作者:檀木丁
連結:https://www.jianshu.com/p/7e8b57d2d74a
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。