lambda表達式,看完了你就是大佬了!

前面一篇文章介紹了兩個經常使用函數式接口SupplierConsumer接口,今天接着講另外另個重要函數式接口PredicateFunction接口。這幾個接口在Java中應用普遍,比方Stream流式API中就常常用到。java

2. Predicate接口

當咱們須要對某種數據類型進行判斷,獲得一個boolean值結果時候,能夠採用java.util.function.Predicate<T>接口。比方說對傳進來的List判斷是否包含某個特定字符PHP。app

2.1 條件判斷

咱們有時候須要進行業務判斷,假設我要實現一個功能入參爲List,若是List參數知足某個條件則輸出對應的結果。比方說下面的代碼checkchar()若是入參list1知足某個條件那麼輸出System.out.println("知足對應條件"),具體條件是什麼還不肯定,多是判斷List中是否包含某個元素,大小是否符合要求。具體由調用方來實現。ide

private static boolean checkChar(List list1, Predicate<List> predicateList) {
        boolean rs = predicateList.test(list1);
        if (rs) {
            System.out.println("知足對應的條件");
        }
        return rs;
    }

下面咱們實現main方法調用上面checkchar()方法,而且經過lambda表達式來實現裏面具體判斷條件。函數

public static void main(String[] args) {
        List list1 = new ArrayList();
        list1.add("PHP");
        list1.add("JAVA");
        list1.add("C++");
        boolean rs = checkChar(list1, s -> {
            return s.contains("PHP");
        });

        if (rs) {
            System.out.println("list1中包含PHP 字符");
        } else {
            System.out.println("list1中不包含PHP 字符");
        }
    }

main方法中,調用checkChar()方法的時候,傳入lambda表達式s-&gt;{return s.contains("PHP")}來進行判斷。這意思就是說在調用checkChar方法的時候若是list1列表中包含PHP這個元素執行System.out.println("知足對應的條件")語句。ui

上述代碼執行結果爲:this

知足對應的條件
list1中包含PHP 字符

2.2 與判斷

上面咱們說了單個條件判斷,若是想多個條件判斷怎麼辦?可使用Predicate的and()方法。code

咱們先定義一個函數,這個函數裏會進行兩個判斷,兩個判斷具體的邏輯由外部傳過來。對象

private static boolean checkChar2(List list1, Predicate<List> pre, Predicate<List> other) {
        return pre.and(other).test(list1);
}

main方法中,傳入兩個判斷邏輯s -&gt; { return s.contains("PHP");}s -&gt; { return s.contains("C++");},而後經過Predicate.and()方法執行與操做。接口

public static void main(String[] args) {
        List list1 = new ArrayList();
        list1.add("PHP");
        list1.add("JAVA");
        list1.add("C++");
        boolean rs = checkChar2(list1, s -> {
            return s.contains("PHP");
        }, s -> {
            return s.contains("C++");
        });

        if (rs) {
            System.out.println("list1同時有PHP和C++字符");
        } else {
            System.out.println("list1不知足同時有PHP和C++字符");
        }
    }

上述代碼的執行結果爲:three

list1同時有PHP和C++字符

2.3 非判斷

"與"、"或"咱們已經瞭解了,剩下還有一個"非"(取反)操做,咱們看一下取反操做negate如何使用。

Predicatenegate()方法以下:

default Predicate<T> negate() {
        return (t) -> !test(t);
 }

從源碼咱們能夠看到negate方法是在執行了test()方法以後,對結果boolean值進行取反而已。請注意,必定要先調用negate方法而後調用test方法 ,這個跟andor方法同樣:

private static boolean checkNotChar(List list1, Predicate<List> pre1) {
        return pre1.negate().test(list1);
}

public static void main(String[] args) {
        List list1 = new ArrayList();
        list1.add("PHP");
        list1.add("JAVA");
        list1.add("C++");
        boolean rs = checkNotChar(list1, s -> {
            return s.contains("C#");
        });

        if (rs) {
            System.out.println("list1沒有C#");
        } else {
            System.out.println("list1有C#");
        }
}

上述代碼執行結果爲:

list1沒有C#

3. Function接口

java.util.function.Function&lt;T,R&gt;至關於數據中的函數,一個類型的數據做爲輸入獲得另外一個類型數據的輸出。

3.1 轉換方法:apply

Function中執行轉換的方法爲抽象方法R apply(T t),該方法根據參數T類型數據獲取類型爲R的結果。好比下面我要將String類型轉化爲Integer類型。具體如何轉換由調用方經過lambda來決定。

咱們先定義轉換的方法:

private static Integer transfer(String param, Function<String, Integer> function) {
        int num = function.apply(param);
        return num;
}

具體轉換邏輯在main方法中定義:

public static void main(String[] args) {
        String str = "99";
        int num = transfer(str, s -> (Integer.parseInt(s) + 1));//這裏定義具體的轉換邏輯
        System.out.println("DemoFunc執行結果爲" + num);
}

3.2 級聯轉換:andThen

若是咱們想作多步轉換那麼就須要用到andThen()方法了,這些具體轉換的實如今調用放經過lambda來實現。

我先定義一個級聯轉換的方法chainTransfer,該方法中傳入三個Function依次通過one,two,three進行轉換,而後返回結果。

private static Integer chainTransfer(String str, Function<String, Integer> one, Function<Integer, Integer> two,
        Function<Integer, Integer> three) {
        int num = one.andThen(two).andThen(three).apply(str);
        return num;
    }

下面在main方法中實現3個Function而後調用轉換函數chainTransfer

public static void main(String[] args) {
        int num = chainTransfer("9", str -> Integer.parseInt(str) + 10, 
                                i -> i *= 10, i -> i + 5);
        System.out.println("轉換後的結果爲:" + num);
    }

咱們執行上面main方法結果爲:

轉換後的結果爲:195

具體轉換步驟爲:

1. 先將9轉換成Integer類型而後+10,對應Integer.parseInt(str) + 10,獲得19;
2. 而後乘以10,獲得19*10 = 190;
3. 第三部加5,獲得190+5 = 195。

固然定義這個方法的時候有一個要注意的,依賴被調用的Function參數類型要是適配,比方說Function&lt;String,Integer&gt; one入參爲String返回值爲Integer,那麼後面Function two的入參必須是Integer。即前一個Function的返回值跟後一個Function入參類型應該兼容。

3.2 討論級聯轉換中的類型兼容問題

前面咱們說了,即前一個Function的返回值跟後一個Function入參類型應該兼容。由於前一個Function是後一個Function的入參,在函數調用中當實際入參是形參的子類那麼是兼容的。

即以下的轉換函數式兼容的:

private static User objChainTransfer(String str, Function<String, VipUser> one, Function<User, User> two) {
        User u = one.andThen(two).apply(str);
        return u;
    }
}

前面一個Function返回的是VipUser,其爲第二個Function的入參User的子類。咱們在main函數中調用上面的函數,其代碼以下:

public static void main(String[] args) {
        User u = objChainTransfer("19", str -> {
            return new VipUser("name" + str, str);
        }, vipUser -> {
            vipUser.setName(vipUser.getName() + "_new");
            return vipUser;
        });

        System.out.println("轉換後的結果爲:" + u);
}

運行後其結果爲:

轉換後的結果爲:VipUser{name='name19_new', id='19'}

這段代碼作了以下事情:

1. 咱們先建立一個`VipUser`對象
2. 修改name屬性,
3. 返回User對象。

進一步咱們能夠分析源碼:

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
 }

源碼中,andThen方法中Function&lt;? super R, ? extends V&gt; after,表示after的這個Function的入參必須是R的超類,其中R是第一個Function的返回值。

具體能夠查看Function.java的源碼:

public interface Function<T, R> {
    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
    //...
}
相關文章
相關標籤/搜索