最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入淺出講解Java8函數(shù)式編程

 更新時(shí)間:2022年01月18日 11:41:49   作者:MongieLee  
不管是前端還是后端開發(fā)人員,學(xué)習(xí)一些函數(shù)式編程的思想和概念,對(duì)于手頭的開發(fā)工作和以后的職業(yè)發(fā)展,都是大有裨益的,下面這篇文章主要給大家介紹了關(guān)于Java8函數(shù)式編程的相關(guān)資料,需要的朋友可以參考下

什么是函數(shù)式編程

函數(shù)式編程就是一種抽象程度很高的編程范式,純粹的函數(shù)式編程語(yǔ)言編寫的函數(shù)沒(méi)有變量,因此,任意一個(gè)函數(shù),只要輸入是確定的,輸出就是確定的,這種純函數(shù)我們稱之為沒(méi)有副作用。而允許使用變量的程序設(shè)計(jì)語(yǔ)言,由于函數(shù)內(nèi)部的變量狀態(tài)不確定,同樣的輸入,可能得到不同的輸出,因此,這種函數(shù)是有副作用的。 函數(shù)式編程的一個(gè)特點(diǎn)就是,允許把函數(shù)本身作為參數(shù)傳入另一個(gè)函數(shù),還允許返回一個(gè)函數(shù)! 函數(shù)式編程最早是數(shù)學(xué)家阿隆佐·邱奇研究的一套函數(shù)變換邏輯,又稱Lambda Calculus(λ-Calculus),所以也經(jīng)常把函數(shù)式編程稱為L(zhǎng)ambda計(jì)算。

Java8內(nèi)置了一些常用的方法接口FunctionalInterface

這種接口只定義了一個(gè)抽象方法,并且用@FunctionalInterface注解標(biāo)記,如Predicate,Consumer,Function,Supplier,Comparator等等,這些都屬于java.util.function包中

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
// 省略不貼了

他們的特點(diǎn)是定義了函數(shù)的入?yún)⒁约胺祷刂担?dāng)使用時(shí)傳入滿足函數(shù)接口定義的表達(dá)式,即可通過(guò)編譯器檢查,下面會(huì)介紹函數(shù)接口和對(duì)應(yīng)的4種使用方式

通過(guò)一個(gè)示例來(lái)看看使用函數(shù)式和不使用的區(qū)別,需求是要有一個(gè)函數(shù),傳入一個(gè)List<Integer>,篩選出單數(shù)的項(xiàng),另一個(gè)則篩選出雙數(shù)的項(xiàng),先看看不使用函數(shù)式的寫法

    // 篩選出單數(shù)的方法
    public static List<Integer> filterSingular(List<Integer> list) {
        List<Integer> result = new ArrayList<>();
        for (Integer item : list) {
            if (item % 2 != 0) {
                result.add(item);
            }
        }
        return result;
    }


    // 篩選出雙數(shù)的方法
    public static List<Integer> filterEven(List<Integer> list) {
        List<Integer> result = new ArrayList<>();
        for (Integer item : list) {
            if (item % 2 == 0) {
                result.add(item);
            }
        }
        return result;
    }

定義方法后調(diào)用,預(yù)期效果輸出[1,3,5,7]和[2,4,5]

        List<Integer> targetList = new ArrayList<Integer>() {
            {
                this.add(1);
                this.add(2);
                this.add(3);
                this.add(4);
                this.add(5);
                this.add(6);
                this.add(7);
            }
        };
        List<Integer> singularList = filterSingular(targetList);
        List<Integer> evenList = filterEven(targetList);
        System.out.println(singularList);
        System.out.println(evenList);

但其實(shí)這兩個(gè)篩選函數(shù),唯一區(qū)別只是判斷條件的不同,這時(shí)候就可以將這個(gè)條件抽象成一個(gè)函數(shù)接口去編寫,Predicate接口的test定義文章開頭就有,傳入一個(gè)泛型類型,返回一個(gè)boolean,改寫下filter的代碼

    public static List<Integer> filter(List<Integer> list,Predicate<Integer> predicate) {
        List<Integer> result = new ArrayList<>();
        for (Integer item : list) {
            if (predicate.test(item)) {
                result.add(item);
            }
        }
        return result;
    }

將函數(shù)改造成了除了傳入目前List外,還要傳入一個(gè)實(shí)現(xiàn)了Predicate接口的實(shí)例對(duì)象,只需要傳入滿足函數(shù)定義入?yún)⒑统鰠ⅲ湍芡ㄟ^(guò)編譯,下面介紹4種這個(gè)函數(shù)的使用方式

  • 使用傳統(tǒng)的匿名內(nèi)部類,在java8之前只能這么操作
        List<Integer> singularList = filter(targetList, new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return integer % 2 != 0;
            }
        });
        System.out.println(singularList);
  • 使用lambda表達(dá)式格式如下()->{},()的是方法列表,->{}是方法體,由于目前只有一個(gè)參數(shù),并且參數(shù)類型是可以推斷出來(lái)的,所以類型和()可以不寫,方法體只有一句,{}也可以不寫,不推薦在方法體中寫過(guò)長(zhǎng)的代碼,應(yīng)保證可讀性
        List<Integer> singularList2 = filter(targetList, integer -> integer % 2 != 0);
        // 下面是完整寫法
        // List<Integer> singularList3 = filter(targetList, (Integer integer) -> {
        //    return integer % 2 != 0;
        // });

可以使用的原因,lambda表達(dá)式滿足傳入Integer返回一個(gè)boolean的抽象操作,可以自動(dòng)轉(zhuǎn)化為函數(shù)接口

  • 靜態(tài)方法引用,這里定義了一個(gè)靜態(tài)方法,也可以自動(dòng)的轉(zhuǎn)化為函數(shù)接口,使用時(shí)需要用雙冒號(hào)語(yǔ)法
    private static boolean integerWithSingular (Integer haha){
        return haha % 2 != 0;
    }

使用靜態(tài)方法引用,Cn是所在類名,這種方式對(duì)比lambda表達(dá)式可以讓可讀性進(jìn)一步提高,因?yàn)榉椒ㄓ忻?,可以通過(guò)名字去判斷在執(zhí)行什么操作,并且更適合編寫更多的邏輯

    List<Integer> singularList3 = filter(targetList, Cn::integerWithSingular);
  • 實(shí)例方法,因?yàn)槿魏螌?shí)例方法,第一個(gè)參數(shù)永遠(yuǎn)都是一個(gè)隱藏的指針this指向當(dāng)前實(shí)例,由于上面例子泛型傳入的是Integer類型,需要改寫下預(yù)期才能演示,先聲明一個(gè)類,并且有一個(gè)實(shí)例方法是完成傳入Test類型返回boolean的映射
public class Test {
    private long id;
    
    public Test(long id) {
        this.id = id;
    }
    
    private boolean integerWithSingular(){
        return this.id % 2 != 0;
    }
}

將filter函數(shù)的Integer類型全換成Test類型

    public static List<Test> filter(List<Test> list, Predicate<Test> predicate) {
        List<Test> result = new ArrayList<>();
        for (Test item : list) {
            if (predicate.test(item)) {
                result.add(item);
            }
        }
        return result;
    }

下面的調(diào)用中,傳入類名::實(shí)例方法名實(shí)現(xiàn)的效果是等價(jià)的

    ArrayList<Test> targetList = new ArrayList<Test>() {
        {
            this.add(new Test(1));
            this.add(new Test(2));
        }
    };
    filter(targetList,Test::integerWithSingular);

任何只包含一個(gè)抽象方法的接口都可以被自動(dòng)轉(zhuǎn)換成函數(shù)接口,自己定義的接口沒(méi)有標(biāo)注@FunctionalInterface標(biāo)注也可以

用的比較多的函數(shù)接口

  • Consumer 輸入一個(gè)對(duì)象,輸出是空的,相當(dāng)于消費(fèi)掉傳入的對(duì)象,ArrayList的forEach方法使用了Consumer
    // ArrayList的forEach方法源碼
    @Override
    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }
  • Function更加接近于函數(shù)的定義,用于將一個(gè)類型變換成另一個(gè)類型,如數(shù)學(xué)中的函數(shù)把X變成Y,函數(shù)接口的定義如下,還是以剛才編寫的Test類為理解,再編寫一個(gè)map方法
    public static String map(Test test, Function<Test, String> function) {
        return function.apply(test);
    }

只要滿足傳入一個(gè)Test類型,返回一個(gè)String類型的東西都可以被自動(dòng)轉(zhuǎn)換

        map(new Test(1),test -> "name");
        
        // 如果Test類型還有一個(gè)屬性為String的name和對(duì)應(yīng)的getter方法,可以寫成下面這種實(shí)例方法引用
        // map(new Test(2), Test::getName);
  • Supplier和Consumer是對(duì)立者,Consumer消費(fèi),Supplier提供,從虛空中提供一個(gè)東西
    public static Object create(Supplier<Object> supplier){
        return supplier.get();
    }

只要滿足憑空冒出一個(gè)東西的條件即可

    create(Object::new);
    // new的作用也是從虛無(wú)創(chuàng)造出一個(gè)對(duì)象,所以可以這么寫
    create(() -> "supplier");
    create(() -> new Test(1));

最后再介紹函數(shù)式編程在排序中的使用

    // Collections.sort的靜態(tài)方法定義
    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }

    // Comparator.comparing的靜態(tài)方法定義
    // 理解成需要傳入一個(gè)T類型映射到U類型的形式即可
    // 對(duì)應(yīng)著示例就是傳入一個(gè)Test,返回一個(gè)實(shí)現(xiàn)了Comparable接口的對(duì)象(如Integer,String...)
    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    }

下面是爽快時(shí)間

    // 使用簡(jiǎn)短的代碼就能實(shí)現(xiàn)按對(duì)象中某個(gè)字段去排序
    public static void main(String[] args) {
        ArrayList<Test> tests = new ArrayList<Test>() {
            {
                this.add(new Test(2, "abc"));
                this.add(new Test(1, "efg"));
            }
        };
        // 現(xiàn)在Test實(shí)例的id字段排序,再將數(shù)組反轉(zhuǎn),然后再按照name字段排序
        Collections.sort(tests, Comparator.comparing(Test::getId)
                .reversed()
                .thenComparing(Test::getName));
        System.out.println(tests);
    }

其他的函數(shù)接口就不再贅述,只要搞懂原理,就能輕松上手使用

總結(jié)

到此這篇關(guān)于Java8函數(shù)式編程的文章就介紹到這了,更多相關(guān)Java8函數(shù)式編程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java代碼獲取jenkins數(shù)據(jù),構(gòu)建歷史等信息方式

    java代碼獲取jenkins數(shù)據(jù),構(gòu)建歷史等信息方式

    這篇文章主要介紹了java代碼獲取jenkins數(shù)據(jù),構(gòu)建歷史等信息方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-05-05
  • Java?9中的"菱形"語(yǔ)法詳解

    Java?9中的"菱形"語(yǔ)法詳解

    Java?9?再次增強(qiáng)了“菱形”語(yǔ)法,它甚至允許在創(chuàng)建匿名內(nèi)部類時(shí)使用菱形語(yǔ)法,Java?可根據(jù)上下文來(lái)推斷匿名內(nèi)部類中泛型的類型,下面程序示范了在匿名內(nèi)部類中使用菱形語(yǔ)法,感興趣的朋友跟隨小編一起看看吧
    2023-06-06
  • Spring Cloud Zuul的重試配置詳解

    Spring Cloud Zuul的重試配置詳解

    這篇文章主要介紹了Spring Cloud Zuul的重試配置詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-04-04
  • Springboot中項(xiàng)目的屬性配置的詳細(xì)介紹

    Springboot中項(xiàng)目的屬性配置的詳細(xì)介紹

    很多時(shí)候需要用到一些配置的信息,這些信息可能在測(cè)試環(huán)境和生產(chǎn)環(huán)境下會(huì)有不同的配置,本文主要介紹了Springboot中項(xiàng)目的屬性配置的詳細(xì)介紹,感興趣的可以了解一下
    2022-01-01
  • Java中常見的語(yǔ)法糖分享

    Java中常見的語(yǔ)法糖分享

    Java語(yǔ)法糖是指Java編譯器在編譯Java源代碼時(shí)所做的一些特殊處理,使得Java源代碼在編譯后生成的字節(jié)碼更加簡(jiǎn)潔、易讀、易維護(hù),Java 中有許多常見的語(yǔ)法糖,本文給大家列舉了一些常見的例子,需要的朋友可以參考下
    2023-10-10
  • java實(shí)現(xiàn)銀行ATM管理系統(tǒng)

    java實(shí)現(xiàn)銀行ATM管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)銀行ATM管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • java中timer的schedule和scheduleAtFixedRate方法區(qū)別詳解

    java中timer的schedule和scheduleAtFixedRate方法區(qū)別詳解

    這篇文章主要為大家詳細(xì)介紹了java中timer的schedule和scheduleAtFixedRate方法區(qū)別,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • SpringBoot中基于JWT的單token授權(quán)和續(xù)期方案步驟詳解

    SpringBoot中基于JWT的單token授權(quán)和續(xù)期方案步驟詳解

    在前后端分離架構(gòu)中,用戶登錄后,后端生成JWT?Token返給前端存于LocalStorage,每次請(qǐng)求攜帶Token驗(yàn)證身份,后端校驗(yàn)其有效性,本文給大家介紹SpringBoot中基于JWT的單token授權(quán)和續(xù)期方案步驟詳解,感興趣的朋友一起看看吧
    2024-09-09
  • java枚舉enum,根據(jù)value值獲取key鍵的操作

    java枚舉enum,根據(jù)value值獲取key鍵的操作

    這篇文章主要介紹了java枚舉enum,根據(jù)value值獲取key鍵的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • 如何解決springboot數(shù)據(jù)庫(kù)查詢時(shí)出現(xiàn)的時(shí)區(qū)差異問(wèn)題

    如何解決springboot數(shù)據(jù)庫(kù)查詢時(shí)出現(xiàn)的時(shí)區(qū)差異問(wèn)題

    這篇文章主要介紹了如何解決springboot數(shù)據(jù)庫(kù)查詢時(shí)出現(xiàn)的時(shí)區(qū)差異問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01

最新評(píng)論

祁连县| 阳新县| 濮阳县| 枞阳县| 林西县| 仪征市| 扶沟县| 湖南省| 原阳县| 武汉市| 襄城县| 南充市| 昌吉市| 澄城县| 安国市| 平谷区| 松桃| 香港| 普定县| 搜索| 伽师县| 务川| 红河县| 会昌县| 绥宁县| 屯昌县| 洪雅县| 密山市| 海原县| 微山县| 乌兰浩特市| 襄城县| 大同县| 华坪县| 师宗县| 眉山市| 金溪县| 奉化市| 昌江| 胶南市| 石屏县|