国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Lambda 表達(dá)式

Null / 1220人閱讀

摘要:例如上一章的蘋果謂詞接口只有一個(gè)抽象方法的接口能讓把整個(gè)表達(dá)式作為函數(shù)式接口的實(shí)例。這個(gè)函數(shù)式接口是用來接收一個(gè)對(duì)象并對(duì)其進(jìn)行處理。

Lambda 管中窺豹

可以把 Lambda 表達(dá)式理解為簡潔地可傳遞的匿名函數(shù)的一種方式:沒有名稱,有參數(shù)列表、函數(shù)主體、返回類型和可能的異常。理論上講,匿名函數(shù)做不到的事,Lambda 也做不了。后者只是讓前者可讀性更強(qiáng),寫得更輕松。

回顧上一章最后的那個(gè) Lambda 表達(dá)式

(Apple apple1) -> "green".equalsIgnoreCase(apple1.getColor()) && 2 == apple1.getWeight()

我們可以發(fā)現(xiàn) Lambda 可以劃分為三個(gè)部分:

參數(shù) (Apple apple1)

箭頭 ->

主體 "green".equalsIgnoreCase(apple1.getColor()) && 2 == apple1.getWeight()

Lambda 的基本語法是這樣的:

(parameters) -> expression

(parameters) -> { statements; }

在哪里以及如何使用 Lambda

我們可以在函數(shù)式接口中使用 Lambda。

函數(shù)式接口就是只定義一個(gè)抽象方法的接口。

例如上一章的蘋果謂詞接口

public interface ApplePredicate {
    boolean test(Apple apple);
}

只有一個(gè)抽象方法的接口能讓 Lambda 把整個(gè)表達(dá)式作為函數(shù)式接口的實(shí)例。匿名內(nèi)部類一樣可以完成同樣的事,只不過很笨拙。

JDK 中的 Runnable 接口

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

兩種實(shí)現(xiàn)方式

        Runnable runnable1 = () -> System.out.println("Hello Word!");
        Runnable runnable2 = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello Word!");
            }
        };

這兩鐘實(shí)現(xiàn)結(jié)果是一樣的。函數(shù)式接口的返回類型基本上就是 Lambda 的返回類型。

函數(shù)式接口一般都可以被 @FunctionalInterface 注解,這個(gè)注解就如同它的名字一樣代表這個(gè)接口是函數(shù)式接口。并且它和 @Override 一樣只是讓編譯期判斷是否正確,運(yùn)行期無關(guān),并不是必需的。如果在一個(gè)接口中定義了多個(gè)抽象方法,并加上這個(gè)注解再編譯的話,編譯器便會(huì)給你的報(bào)錯(cuò),因?yàn)檫@樣的接口已經(jīng)不符合函數(shù)式接口的定義了。

使用函數(shù)式接口

JDK 本身也自帶了幾個(gè)函數(shù)式接口,比如 Predicate、Consumer、Function。我們可以使用一下練練手。

Predicate

這個(gè)和上一章最后我們自己寫的那個(gè)函數(shù)式接口,兩者完全一樣,都是用來做條件測(cè)試的謂詞接口。

通過謂詞過濾泛型集合

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

過濾掉字符串集合中空字符串

        List stringList = new ArrayList<>();
        stringList.add("hello");
        stringList.add("");
        stringList.add("lambda");

        // Lambda 實(shí)現(xiàn)
        Predicate stringPredicate = (String s) -> !s.isEmpty();
        // 匿名實(shí)現(xiàn)
        Predicate stringPredicate1 = new Predicate() {
            @Override
            public boolean test(String s) {
                return !s.isEmpty();
            }
        };
        List result = filter(stringList, stringPredicate);

這樣空字符串就會(huì)被過濾掉,只剩下 hellolambda

Consumer

這個(gè)函數(shù)式接口是用來接收一個(gè)對(duì)象并對(duì)其進(jìn)行處理。

遍歷一個(gè)泛型集合

    public static  void forEach(List list, Consumer consumer) {
        for (T t : list) {
            consumer.accept(t);
        }
    }

取出字符串集合里面的對(duì)象并打印輸出

        // Lambda 實(shí)現(xiàn)
        Consumer consumer = (String s) -> System.out.println(s);
        // 匿名實(shí)現(xiàn)
        Consumer consumer1 = new Consumer() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        forEach(stringList, consumer);

這樣就會(huì)打印輸出 hello、 、lambda

Function

這個(gè)函數(shù)式接口是用來接收一個(gè)對(duì)象并映射到另一個(gè)對(duì)象。

接收一個(gè)集合對(duì)象并返回另一個(gè)集合對(duì)象

    public static  List map(List list, Function function) {
        List result = new ArrayList<>();
        for (T t : list) {
            result.add(function.apply(t));
        }
        return result;
    }

接收一個(gè)字符串集合并映射成其長度的整型集合后返回

        // Lambda 實(shí)現(xiàn)
        Function function = (String s) -> s.length();
        // 匿名實(shí)現(xiàn)
        Function function1 = new Function() {
            @Override
            public Integer apply(String s) {
                return s.length();
            }
        };
        List integerList = map(stringList, function);

這樣 hello、 、lambda 就分別對(duì)應(yīng)其長度 506

方法引用

方法引用可以看作對(duì)特定 Lambda 的一種快捷寫法,本質(zhì)上依然是 Lambda。它的基本思想是,如果一個(gè) Lambda 代表的僅僅是 直接調(diào)用 這個(gè)方法而不是 描述如何去調(diào)用 這個(gè)方法,那最好還是用名稱來調(diào)用它。

例如在上一章的蘋果實(shí)例中我們需要用謂詞判斷是否成熟

        // 普通 Lambda 寫法
        Predicate applePredicate1 = (Apple apple) -> apple.isAging();
        // 方法引用寫法
        Predicate applePredicate2 = Apple::isAging;

我們可以把方法引用看作對(duì) 僅僅涉及單一方法 的 Lambda 的語法糖。

構(gòu)造函數(shù)引用

對(duì)于一個(gè)現(xiàn)有的構(gòu)造函數(shù),我們可以利用它的名稱和 new 來創(chuàng)建它的一個(gè)引用:ClassName::new

        // 普通 Lambda 創(chuàng)建對(duì)象
        // Supplier appleSupplier = () -> new Apple();
        // 構(gòu)造函數(shù)引用創(chuàng)建無參對(duì)象
        Supplier appleSupplier = Apple::new;
        // 獲取實(shí)例
        Apple apple1 = appleSupplier.get();
        
        // 構(gòu)造函數(shù)引用創(chuàng)建有一個(gè)參數(shù)對(duì)象
        Function appleFunction = Apple::new;
        // 獲取實(shí)例
        Apple apple2 = appleFunction.apply("red");

        // 構(gòu)造函數(shù)引用創(chuàng)建有兩個(gè)參數(shù)對(duì)象
        BiFunction appleBiFunction = Apple::new;
        // 獲取實(shí)例
        Apple apple3 = appleBiFunction.apply("red", 1);

那么當(dāng)參數(shù)有很多的時(shí)候怎么辦呢?我們可以自定義一個(gè)函數(shù)式接口進(jìn)行處理。

三個(gè)參數(shù)的構(gòu)造函數(shù)引用接口

public interface TriFunction {
    R apply(T t, U u, V v);
}

調(diào)用也是類似的

        // 構(gòu)造函數(shù)引用創(chuàng)建有三個(gè)參數(shù)對(duì)象
        TriFunction appleTriFunction = Apple::new;
        // 獲取實(shí)例
        Apple apple4 = appleTriFunction.apply("red", 1, true);
Lambda 和方法引用實(shí)戰(zhàn) 傳遞代碼

我們?nèi)绻獙?duì)一個(gè)蘋果集合按照重量從小到大排序,首先肯定要進(jìn)行判斷大小,然后對(duì)其進(jìn)行排序。按照我們已經(jīng)經(jīng)過一章多的學(xué)習(xí),應(yīng)該能很輕松地構(gòu)建一個(gè)解決方案。

1、創(chuàng)建比較器

public class AppleComparator implements Comparator {
    @Override
    public int compare(Apple o1, Apple o2) {
        return o1.getWeight().compareTo(o2.getWeight());
    }
}

2、調(diào)用 List 已經(jīng)實(shí)現(xiàn)好的排序方法

public class Main {
    public static void main(String[] args) {
        List appleList = new ArrayList<>();

        // 重量為2的成熟紅蘋果 No.1
        Apple apple = new Apple();
        apple.setColor("red");
        apple.setWeight(2);
        apple.setAging(true);
        appleList.add(apple);

        // 重量為1的未成熟綠蘋果 No.2
        apple = new Apple();
        apple.setColor("green");
        apple.setWeight(1);
        apple.setAging(false);
        // 現(xiàn)在 appleList 的順序是放入的順序 No.1、No.2
        appleList.add(apple);

        // 依照重量排序后 appleList 的順序會(huì)變成 No.2、No.1
        appleList.sort(new AppleComparator());
    }
}

這只是簡單的一個(gè)通過傳遞比較器來進(jìn)行排序。下面我們會(huì)用匿名類來實(shí)現(xiàn)上一章學(xué)習(xí)的 應(yīng)對(duì)不斷變化的需求

使用匿名類

到這一步其實(shí)已經(jīng)算得上符合正常軟件工程設(shè)計(jì)了,可以舍去 AppleComparator 這樣的實(shí)現(xiàn)方式。

        appleList.sort(new Comparator() {
            @Override
            public int compare(Apple o1, Apple o2) {
                return o1.getWeight().compareTo(o2.getWeight());
            }
        });
使用 Lambda 表達(dá)式

緊接著我們可以更加高效地用 Lambda 實(shí)現(xiàn)。

        appleList.sort((Apple o1, Apple o2) -> o1.getWeight().compareTo(o2.getWeight()));

我們還可以進(jìn)一步簡化代碼。Java 編譯器會(huì)從目標(biāo)類型自動(dòng)推斷出適合 Lambda 的返回類型。因此可以省略對(duì)傳入?yún)?shù)的類型定義。

        // appleList 的類型定義是 List,傳遞進(jìn) sort() 的 Comparator 會(huì)自動(dòng)定義泛型為 Apple,所以 Lambda 也可以自動(dòng)推斷為 Comparator 的 compare() 傳入的類型。
        appleList.sort((o1, o2) -> o1.getWeight().compareTo(o2.getWeight()));
使用方法引用

使用方法引用還可以更加讓人通俗易懂。

Comparator 有個(gè)靜態(tài)方法 comparing 可以接收 Function 函數(shù)式接口,用作比較依據(jù)。

        // 傳入的 Function 本質(zhì)是將蘋果(Apple)映射成了蘋果的重量(Integer)
        // Function function = (Apple o1) -> o1.getWeight();
        // 方法引用后
        Function function = Apple::getWeight;
        // 傳入到 comparing 靜態(tài)方法
        Comparator.comparing(function);

所以最后可以簡化到極致

        // 代表按照蘋果的重量進(jìn)行比較后排序
        appleList.sort(Comparator.comparing(Apple::getWeight));
復(fù)合 Lambda 表達(dá)式的有用方法

Java 8提供了允許進(jìn)行復(fù)合的方法。比如我們可以讓兩個(gè)謂詞之間做 or 操作,組成一個(gè)更加強(qiáng)大的謂詞。

比較器復(fù)合

如果想要從大到小排序蘋果的重量(默認(rèn)的 sort() 是從小到大排序)

        appleList.sort(Comparator.comparing(Apple::getWeight).reversed());

但是如果兩個(gè)的蘋果重量一樣,我們需要再根據(jù)顏色或者是否成熟來排序呢?

我們可以使用 thenComparing 方法

        appleList.sort(Comparator
                // 從大到小排列蘋果的重量
                .comparing(Apple::getWeight).reversed()
                // 然后按照顏色字母順序
                .thenComparing(Apple::getColor)
                // 然后按照是否成熟
                .thenComparing(Apple::getAging));

這樣就可以創(chuàng)建一個(gè)比較器鏈了。

謂詞復(fù)合

謂詞接口包括三個(gè)方法:negate、and 和 or,我們可以以此創(chuàng)建復(fù)雜的謂詞。

選出蘋果不是紅的

        Predicate isRed = (Apple o1) -> "red".equalsIgnoreCase(o1.getColor());
        Predicate noRed = isRed.negate();

選出蘋果不是紅的且成熟的

        Predicate noRedAndIsAging = noRed.and(Apple::getAging);

選出蘋果不是紅的且成熟的或重量大于1

        Predicate noRedAndIsAgingOrHeavey = noRedAndIsAging.or((Apple o1) -> o1.getWeight() > 1);

總結(jié)起來,除了 isRed 謂詞要在第一步寫,其余的地方都可以一句話寫完

        Predicate predicate = noRed
                .and(Apple::getAging)
                .or((Apple o1) -> o1.getWeight() > 1);

這樣從簡單的 Lambda 出發(fā),可以構(gòu)建更加復(fù)雜的表達(dá)式,但讀起來會(huì)更加輕松。注意,and 和 or 的是按照鏈中的位置執(zhí)行。

函數(shù)復(fù)合

Function 接口包括兩個(gè)方法:andThen 和 compose,它們都會(huì)返回一個(gè) Function 的實(shí)例。

我們可以用 Function 定義三個(gè)函數(shù) f(x)、g(x)和 g(x),先看看 andThen()

        // f(x) = x + 1
        Function f = x -> x + 1;
        // g(x) = x * 2
        Function g = x -> x * 2;
        // h(x) = f(g(x))
        Function h = f.andThen(g);

傳入 x 進(jìn)行運(yùn)算

        // 結(jié)果為4
        int result = h.apply(1);

compose()

        // h(x) = g(f(x))
        h = f.compose(g);
        // 結(jié)果為3
        result = h.apply(1);

第三章的東西有點(diǎn)多,需要反復(fù)消化理解。

Java 8 實(shí)戰(zhàn) 第三章 Lambda 表達(dá)式 讀書筆記

歡迎加入咖啡館的春天(338147322)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/70186.html

相關(guān)文章

  • JAVA Lambda達(dá)式

    摘要:語言是強(qiáng)類型面向?qū)ο蟮恼Z言,所以必須提供一種數(shù)據(jù)類型作為表達(dá)式的返回值類型符合中函數(shù)格式的定義符合面向?qū)ο笠?guī)則,所以最終表達(dá)式要有一個(gè)映射成對(duì)象的過程。定一個(gè)函數(shù)式接口我們?cè)诮涌诶锒x了一個(gè)沒有參數(shù)返回值的抽象方法。 在JAVA中,Lambda 表達(dá)式(Lambda expression)是一個(gè)抽象方法的實(shí)現(xiàn)。這個(gè)抽象方法必須是在接口中聲明的,而且實(shí)現(xiàn)類只需要實(shí)現(xiàn)這一個(gè)抽象方法,我們稱...

    Cheng_Gang 評(píng)論0 收藏0
  • Java Lambda達(dá)式

    摘要:表達(dá)式的主要作用就是代替匿名內(nèi)部類的煩瑣語法。從這點(diǎn)來看,表達(dá)式的代碼塊與匿名內(nèi)部類的方法體是相同的。與匿名內(nèi)部類相似的是,由于表達(dá)式訪問了局部變量,該局部變量相當(dāng)于與一個(gè)隱式的修飾,因此不允許對(duì)局部變量重新賦值。 函數(shù)式接口 函數(shù)式接口(Functional Interface)就是一個(gè)只有一個(gè)抽象方法(可以包含多個(gè)默認(rèn)方法或多個(gè)static方法)的普通接口,可以被隱式轉(zhuǎn)換為lamb...

    lewif 評(píng)論0 收藏0
  • 深入淺出 Java 8 Lambda 達(dá)式

    摘要:在支持一類函數(shù)的語言中,表達(dá)式的類型將是函數(shù)。匿名函數(shù)的返回類型與該主體表達(dá)式一致如果表達(dá)式的主體包含一條以上語句,則表達(dá)式必須包含在花括號(hào)中形成代碼塊。注意,使用表達(dá)式的方法不止一種。 摘要:此篇文章主要介紹 Java8 Lambda 表達(dá)式產(chǎn)生的背景和用法,以及 Lambda 表達(dá)式與匿名類的不同等。本文系 OneAPM 工程師編譯整理。 Java 是一流的面向?qū)ο笳Z言,除了部分簡...

    wdzgege 評(píng)論0 收藏0
  • Java 8 Lambda 達(dá)式詳解

    摘要:表達(dá)式簡介表達(dá)式是一個(gè)匿名函數(shù)對(duì)于而言并不很準(zhǔn)確,但這里我們不糾結(jié)這個(gè)問題。如果表達(dá)式的正文有一條以上的語句必須包含在大括號(hào)代碼塊中,且表達(dá)式的返回值類型要與匿名函數(shù)的返回類型相同。 版權(quán)聲明:本文由吳仙杰創(chuàng)作整理,轉(zhuǎn)載請(qǐng)注明出處:https://segmentfault.com/a/1190000009186509 1. 引言 在 Java 8 以前,若我們想要把某些功能傳遞給某些方...

    haoguo 評(píng)論0 收藏0
  • 轉(zhuǎn) | Java8初體驗(yàn)(一)lambda達(dá)式語法

    摘要:初體驗(yàn)下面進(jìn)入本文的正題表達(dá)式。接下來展示表達(dá)式和其好基友的配合。吐槽一下方法引用表面上看起來方法引用和構(gòu)造器引用進(jìn)一步簡化了表達(dá)式的書寫,但是個(gè)人覺得這方面沒有的下劃線語法更加通用。 感謝同事【天錦】的投稿。投稿請(qǐng)聯(lián)系 tengfei@ifeve.com 本文主要記錄自己學(xué)習(xí)Java8的歷程,方便大家一起探討和自己的備忘。因?yàn)楸救艘彩莿倓傞_始學(xué)習(xí)Java8,所以文中肯定有錯(cuò)誤和理解偏...

    Lucky_Boy 評(píng)論0 收藏0
  • 函數(shù)式編程與面向?qū)ο缶幊蘙1]: Lambda達(dá)式 函數(shù)柯里化 高階函數(shù)

    摘要:函數(shù)式編程與面向?qū)ο缶幊瘫磉_(dá)式函數(shù)柯里化高階函數(shù)之劍什么是表達(dá)式例子定義表達(dá)式是一個(gè)匿名函數(shù),表達(dá)式基于數(shù)學(xué)中的演算得名,直接對(duì)應(yīng)于其中的抽象,是一個(gè)匿名函數(shù),即沒有函數(shù)名的函數(shù)。 函數(shù)式編程與面向?qū)ο缶幊蘙1]: Lambda表達(dá)式 函數(shù)柯里化 高階函數(shù).md 之劍 2016.5.2 11:19:09 什么是lambda表達(dá)式 例子 For example, in Lisp the...

    張金寶 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<