<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 495,comments - 227,trackbacks - 0
    http://unmi.cc/jdk8-lambda-method-references/

    Lambda 允許我們定義匿名方法(即那個(gè) Lambda 表達(dá)式,或叫閉包),作為一個(gè)功能性接口的實(shí)例。如果你不想把一個(gè) Lambda 表達(dá)式寫得過大,那么你可以把表達(dá)式的內(nèi)容分離出來寫在一個(gè)方法中,然后在放置 Lambda 表達(dá)式的位置上填上對那個(gè)方法的引用。

    方法引用也應(yīng)看作是一個(gè) Lambda 表達(dá)式,所以它也需要一個(gè)明確的目標(biāo)類型充當(dāng)功能性接口的實(shí)例。簡單說就是被引用的方法要與功能接口的 SAM(Single Abstract Method) 參數(shù)、返回類型相匹配。方法引用的引入避免了 Lambda 寫復(fù)雜了可讀性的問題,也使得邏輯更清晰。

    為了應(yīng)對方法引用這一概念, JDK8 又重新借用了 C++ 的那個(gè) “::” 域操作符,全稱為作用域解析操作符。

    上面的表述也許不好明白,我看官方的那份 State of the Lambda 也覺得不怎么容易理解,特別是它舉了那個(gè)例子很難讓人望文生意。我用個(gè)自己寫的例子來說明一下吧。

    目前的 Eclipse-JDK8 版還不能支持方法引用的特性,幸好就是在昨天正式版的 NetBeans IDE 7.4 對 JDK8 有了較好的支持,所以在 NetBeans 7.4 中寫測試代碼。

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    package testjdk8;
     
    /**
     *
     * @author Unmi
     */
    public class TestJdk8 {
     
        public static void main(String[] args) {
            //使用 Lambda 表達(dá)式,輸出: 16: send email
            start((id, task) -> id + ": " + task);
            //或者
            Machine m1 = (id, task) -> id + ": " + task;
            m1.doSomething(16, "send email");
             
            //使用方法引用,輸出: Hello 16: send email
            start(TestJdk8::hello);
            //或者
            Machine m2 = TestJdk8::hello;
            m2.doSomething(16, "send email");
        }
         
        private static void start(Machine machine){
            String result = machine.doSomething(16, "send email");
            System.out.println(result);
        }
         
        public static String hello(int id, String task){
            return "Hello " + id +": " + task;
        }
    }
     
    @FunctionalInterface
    interface Machine {
        public String doSomething(int id, String task);
    }

    說明:

    1. Machine 是一個(gè)功能性接口,它只有一個(gè)抽象方法
    2. start(Machine machine) 方法為 Lambda 表達(dá)式提供了一個(gè)上下文,表明它期盼接收一個(gè) Machine 的功能性接口類型
    3. start((id, task) -> id + ": " + task), 是傳遞了一個(gè) Lambda 表達(dá)式給 start() 方法
    4. start(TestJdk8::hello) 是把指向 TestJdk8::hello 方法的引用傳遞給了 start() 方法,這里可以理解 hello() 方法是 Lambda 表達(dá)式的另一種表現(xiàn)形式。

    對應(yīng)一下兩個(gè) start() 方法調(diào)用的參數(shù),Lambda 表達(dá)式的參數(shù)列表 (id, task) 與 hello 方法的參數(shù) (int id, String task) 是一致的,返回值類型也是一致的。

    想像一下如果一個(gè) Lambda 表達(dá)式的代碼量很大,全部擠在一起作為 start() 方法的參數(shù)部分,混亂也不太方便于單步調(diào)試。所以可以把 Lambda 的實(shí)現(xiàn)挪出來放在一個(gè)單獨(dú)的方法中,在使用處只放置一個(gè)對該方法的引用即可。借助于方法引用,JDK8  把方法與 Lambda 表達(dá)式巧妙的結(jié)合了起來,直接的說 Lambda 表達(dá)就是一個(gè)方法,它用自己的方法列表和返回值。

    那么符合什么條件的方法可以作為 Lambda 表達(dá)式來用呢?答:方法簽名與功能性接口的 SAM 一致即可。比如,可以進(jìn)行下面的賦值:

    1
    2
    Consumer<Integer> b1 = System::exit //void exit(int status) 與 Consumer 的 SAM void accept(T t) 相匹配
    Runnable r = MyProgram::main;      //void main(String... args) 與 run() 方法能配上對

    有些什么樣子的方法引用:

    1. 靜態(tài)方法 (ClassName::methName)
    2. 對象的實(shí)例方法 (instanceRef::methName)
    3. 對象的super 方法 (super::methName)
    4. 類型的實(shí)例方法 (ClassName::methName, 引用時(shí)和靜態(tài)方法是一樣的,但這里的 methName 是個(gè)實(shí)例方法)
    5. 類的構(gòu)造方法 (ClassName::new)
    6. 數(shù)組的構(gòu)造方法 (TypeName[]::new)

    第 1 條,靜態(tài)方法以 ClassName 為作用域好理解,第 4 條中實(shí)例方法也可以用 ClassName::methName 的方式去引用,那么這里又有個(gè)約定了:如果實(shí)例方法用類型來引用的時(shí)候,那么調(diào)用時(shí)第一個(gè)參數(shù)將作為該引用方法的接收者,其余參數(shù)依次作為引用方法的參 數(shù)。舉個(gè)例子:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    package testjdk8;
     
    import java.util.function.Function;
     
    /**
     *
     * @author Unmi
     */
    public class TestJdk8 {
     
        public static void main(String[] args) {
            Function<String, String> upperfier = String::toUpperCase;
            System.out.println(upperfier.apply("Hello")); //HELLO
             
            Machine m = TestJdk8::hello; //hello 是實(shí)例方法
            TestJdk8 test = new TestJdk8();
            //test 作為 hello 方法的接收者,"Unmi" 作為 task 參數(shù)
            System.out.println(m.doSomething(test, "Unmi")); //Hello Unmi
        }
         
        public String hello(String task){
            return "Hello " + task;
        }
    }
     
    @FunctionalInterface
    interface Machine {
        public String doSomething(TestJdk8 test, String task);
    }

    上面的代碼應(yīng)該能有助于理解實(shí)例方法用類型來引用,如果引用的是泛型方法,類型寫在 :: 之前。

    同樣當(dāng)然對于第 2 條,引用實(shí)例方法時(shí),SAM 的第一個(gè)參數(shù)也作為接收者,其作參數(shù)依次填充過去。

    第 5 條,類的構(gòu)造方法要用類型去引用,new 相當(dāng)一個(gè)返回當(dāng)前類型實(shí)例的實(shí)例方法,所以

    1
    2
    SocketImplFactory factory = MySocketImpl::new;
    SocketImpl socketImpl = factory.createSocketImpl();

    數(shù)組是種類型,可以認(rèn)為數(shù)組的構(gòu)造方法是只接受一個(gè)整形參數(shù),所以能這樣引用數(shù)組的構(gòu)造方法:

    1
    2
    IntFunction<int[]> arrayMaker = int[]::new;
    int[] array = arrayMaker.apply(10);  // creates an int[10]
    小結(jié):Lambda 表達(dá)式就是一個(gè)功能性接口的實(shí)例,因而調(diào)用方式參照功能性接口。Lambda 表達(dá)式可抽取到一個(gè)方法中,然后用方法引用指向這個(gè)方法,被引用的方法簽名與功能性接口的 SAM 的一致性,注意引用實(shí)例方法時(shí),SAM 的第一個(gè)參數(shù)將作為引用方法的接收者。我們把數(shù)組理解為有一個(gè)接收整數(shù)的構(gòu)造方法。
    posted on 2014-12-25 16:08 SIMONE 閱讀(2409) 評論(0)  編輯  收藏 所屬分類: JAVA
    主站蜘蛛池模板: 亚洲欧洲日本精品| 四虎永久在线精品视频免费观看| A级毛片成人网站免费看| 偷自拍亚洲视频在线观看| 国产成人亚洲综合在线| 国产成人亚洲毛片| 老外毛片免费视频播放| 黄色免费在线网址| 特级毛片A级毛片免费播放| 又长又大又粗又硬3p免费视频| 青青久久精品国产免费看| 又长又大又粗又硬3p免费视频 | 免费大黄网站在线看| 国产精品四虎在线观看免费| 国产大片91精品免费观看男同 | 男人的好看免费观看在线视频| 免费看韩国黄a片在线观看| 成**人免费一级毛片| 成在线人永久免费视频播放| 啊灬啊灬别停啊灬用力啊免费看| 亚洲成av人片在线观看天堂无码| 久久亚洲国产精品五月天婷| 亚洲精品国产精品乱码不卡√| 亚洲自偷自拍另类12p| 亚洲第一香蕉视频| 亚洲综合一区国产精品| 黄色a三级三级三级免费看| 中文字幕成人免费高清在线视频| 性色午夜视频免费男人的天堂| 国产精品色拉拉免费看| 日韩成人免费aa在线看| 久久久久国产亚洲AV麻豆| 亚洲国产一区在线| 亚洲日本成本人观看| 污视频网站免费在线观看| 中文无码成人免费视频在线观看| 亚洲一区二区免费视频| 国产美女a做受大片免费| 亚洲午夜久久久久久久久久| 亚洲第一成年网站大全亚洲| 亚洲av日韩综合一区二区三区|