用Java DIY 函數(shù)式方法—— forEach, find, filter

背景

接觸過Kotlin, RxJava蚂且, Java 8 Stream开镣, 越發(fā)對其中常用方法涉及的原理有點(diǎn)了解了殴蹄。

  • forEach
  • find
  • filter
  • map
  • flatmap

知道他們的作用哗咆,也知道如何去使用蜘欲, 但是對其中的大概原理不是很明白益眉。最近熟悉Java8的Stream中提供的幾個常用方法晌柬。 試著自己用java方式實(shí)現(xiàn)了類似java8 Stream中的函數(shù)式方法。

接下來郭脂,會有3篇文章介紹年碘,如何不使用java 8 stream特性,來實(shí)現(xiàn)函數(shù)式常用方法, 通過這三篇文章展鸡,也能讓讀者理解其他函數(shù)式語言中的相關(guān)方法原理

  • 用Java DIY 函數(shù)式方法—— forEach, find, filter
  • 用Java DIY 函數(shù)式方法—— map
  • 用Java DIY 函數(shù)式方法—— flatmap

注意

  • 不適合對函數(shù)式一點(diǎn)基礎(chǔ)都沒有的讀者
  • DIY實(shí)現(xiàn)不是完美的屿衅,僅僅是用實(shí)例表達(dá)函數(shù)式方法的理解
  • 這個系列文章不是分析java 8 stream中的方法源碼,而是對java 8 stream特性莹弊,結(jié)合Kotlin涤久, Rxjava之類的理解, 使用純java的方式實(shí)現(xiàn)類似的函數(shù)式方法忍弛。
  • 需要對java 中的泛型以及Collection有了解
  • 會用到j(luò)ava 8 lambda表達(dá)式
  • 要實(shí)際代碼驗(yàn)證响迂,需要 jdk 1.8

講解的模式如下:

  • 給出某個場景
  • 使用 java 8
  • 使用DIY 函數(shù)實(shí)現(xiàn)

那就進(jìn)入主題吧: 用Java DIY 函數(shù)式方法—— forEach, find, filter

DIY 函數(shù)式方法

forEach

作用: forEach 遍歷集合中的每個元素,對每個元素做操作

        /** 需求:
         * 給定一個String集合细疚,然后遍歷蔗彤,打印出集合中每個元素
         */

我X, 這是哪門子需求疯兼,直接來個循環(huán)不就解決了么然遏?
大兄弟,莫發(fā)脾氣吧彪,靜下心來待侵,慢慢看下。

1. java 8 Iterable.forEach

java 8 在Iterable上添加了新方法 forEach姨裸, 同時也在Stream類中添加了forEach方法

List<String> list = Arrays.asList("Hello", "World!");
list.forEach(new Consumer<String>() {
            @Override
            public void accept(String item) {
                out.println(item);
            }
        });

為什么這么寫秧倾,自己查看forEach方法的定義。使用lambda表達(dá)式啦扬,更簡潔

list.forEach(item -> out.println(item));

從上述可以簡單得到中狂,在java中 lambda表達(dá)式就是用來替代匿名接口實(shí)現(xiàn)的!

2. java 8 Stream.forEach

List<String> list = Arrays.asList("Hello", "World!");
list.stream().forEach(new Consumer<String>() {
            @Override
            public void accept(String item) {
                out.print(item + " ");
            }
        });

使用lambda表達(dá)式扑毡,更簡潔

list.stream().forEach(item -> out.print(item + " "));

3. DIY forEach

簡單起見胃榕,這里使用函數(shù)形式,而不是java 8 stream那樣單獨(dú)類,使用鏈?zhǔn)秸{(diào)用勋又。
再看一次

forEach原理: 遍歷集合中的每一個元素苦掘,然后對其進(jìn)行我們想要的操作

注意其中 2點(diǎn):

  • 遍歷
  • 對每個item都有操作

所以,需要把forEach方法設(shè)計為

    public static <T> void forEach(Collection<T> collection, Action<T> action){
        for(T item: collection){
            action.call(item);
        }
    }
    public interface Action<T> {
        void call(T item);
    }

說明: Action<T> 是泛型接口楔壤,其中call對item操作的方法鹤啡!
forEach方法2個參數(shù),第一個參數(shù)是需要處理的泛型集合蹲嚣, 第二個參數(shù)是操作處理递瑰。
并且,具體的對每個item做什么事情隙畜,在調(diào)用時候傳入抖部!
如何使用?

List<String> list = Arrays.asList("Hello", "World!");
forEach(list, new Action<String>() {
            @Override
            public void call(String item) {
                out.println(item);
            }
        });

說明: 使用很簡單议惰,就是打印出List中的每個String慎颗, 當(dāng)然你也可以在call方法中做其他的操作。

lambda簡化

forEach(list, item -> out.println(item));

接下來言询,實(shí)現(xiàn)我們自己的filter函數(shù)俯萎, 這個是函數(shù)式編程中經(jīng)常使用的函數(shù)

filter

作用: 過濾Collection中符合條件的元素集合
簡化描述 T -> R

         /** 需求:
         *過濾出 [1, 2, ... 10]中是偶數(shù)的集合, 并打印出來!
         */

1. java 8 stream

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
integerList.stream()
                .filter(new Predicate<Integer>() {
                    @Override
                    public boolean test(Integer integer) {
                        return integer % 2 == 0; //判斷條件
                    }
                })
                .forEach(out::println);

lambda簡化版本

integerList.stream()
                .filter(integer -> (integer % 2 == 0))
                .forEach(out::println);

2. DIY filter

需要明確 filter 的作用是將 T -> T运杭, 可以理解為將集合 T 轉(zhuǎn)換為 集合 T夫啊, 其中后面的是前面的子集!

注意其中 2點(diǎn):

  • 遍歷
  • 有判斷操作

所以县习,filter函數(shù)設(shè)計為:

    public static <T> Collection<T> filter(Collection<T> collection, Perdicate<T> perdicate ) {
        Collection<T> result = new ArrayList<>();
        for(T item : collection){
            if(perdicate.call(item)) {
                result.add(item);
            }
        }
        return result;
    }

    public interface Perdicate<T> { 
        boolean call(T item);  //判斷方法
    }

說明: Perdicate<T> 是泛型接口涮母,其中perdicate.call(item)是對item的判斷,滿足條件加入到result 集合中
如何使用躁愿?

filter(integerList, new Perdicate<Integer>() {
            @Override
            public boolean call(Integer item) {
                return item % 2 == 0;
            }
        }).forEach(out::println);

lambda簡化:

filter(integerList, item -> item % 2 == 0).forEach(out::println);

再如叛本, 找出集合["a1", "ab1", "a1", "ab2", "ac"]中全部 “a1”元素, 并打印

filter(Arrays.asList("a1", "ab1", "a1", "ab2", "ac"), item -> item.equals("a1")).forEach(out::println);

仔細(xì)看彤钟,邏輯清晰来候,寫法簡潔!

接下來逸雹,實(shí)現(xiàn)我們自己的find函數(shù)营搅, 這個是函數(shù)式編程中經(jīng)常使用的函數(shù)

find

作用: 找到集合中的第一個元素

注意, java 8 中提供了2個函數(shù)梆砸,findFirst转质, findAny, 為了簡單帖世,這里就是選擇返回集合第一個元素休蟹!

        /** 需求:
         * [1, 2, ... 10]中的第一個元素
         */

1. java 8 stream.findFirst

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
out.println(integerList.stream().findFirst().get());

2. DIY find

public static <T> T find(Collection<T> collection){
        return collection.stream().findFirst().get();// 直接復(fù)用 stream 方法
}

小結(jié)

通過java 8 stream 和 DIY 函數(shù)對比,發(fā)現(xiàn)在Collection基礎(chǔ)上也是可以做到類似stream提供的函數(shù)。
大概揭示赂弓, 函數(shù)式常用方法的原理绑榴!
以上三個比較好理解,下篇的map盈魁,以及flatmap翔怎,不是很好理解!
代碼上傳到csdn 資源下載

喜歡杨耙,用實(shí)際點(diǎn)贊支持我吧赤套! 歡迎留言討論!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末按脚,一起剝皮案震驚了整個濱河市于毙,隨后出現(xiàn)的幾起案子敦冬,更是在濱河造成了極大的恐慌辅搬,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脖旱,死亡現(xiàn)場離奇詭異堪遂,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)萌庆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門溶褪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人践险,你說我怎么就攤上這事猿妈。” “怎么了巍虫?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵彭则,是天一觀的道長。 經(jīng)常有香客問我占遥,道長俯抖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任瓦胎,我火速辦了婚禮芬萍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘搔啊。我一直安慰自己柬祠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布负芋。 她就那樣靜靜地躺著漫蛔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惩猫,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天芝硬,我揣著相機(jī)與錄音,去河邊找鬼轧房。 笑死拌阴,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的奶镶。 我是一名探鬼主播迟赃,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼厂镇!你這毒婦竟也來了纤壁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤捺信,失蹤者是張志新(化名)和其女友劉穎酌媒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迄靠,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡秒咨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了掌挚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雨席。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖吠式,靈堂內(nèi)的尸體忽然破棺而出陡厘,到底是詐尸還是另有隱情,我是刑警寧澤特占,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布糙置,位于F島的核電站,受9級特大地震影響摩钙,放射性物質(zhì)發(fā)生泄漏罢低。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一胖笛、第九天 我趴在偏房一處隱蔽的房頂上張望网持。 院中可真熱鬧,春花似錦长踊、人聲如沸功舀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辟汰。三九已至列敲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間帖汞,已是汗流浹背戴而。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留翩蘸,地道東北人所意。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像催首,于是被迫代替她去往敵國和親扶踊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容