使用Lambda表達式建立接口對象高效編程

一、前言

在java8中,增長了函數接口、Lambda和方法引用,使得建立函數對象變得很容易高效,本文經過情景引入,具體說明一下使用Lambda表達式建立接口對象是如何提升編程效率的。固然文中的所涉及的並不是Lambda的所有使用場景。java

二、代碼情景導入

咱們已有共識:Java是面向對象的編程語言,若是咱們調用任何一個對象的方法,並往方法中傳遞參數,參數必須是類或接口的對象或者是基本類型變量。
按照這個共識,咱們看下面的代碼:編程

//定義一個接口
interface Example{
    //接口中只定義了一個抽象方法
    void add(Integer a,Integer b);
}
//接口的實現類
class ExampleImpl implements Example {
    @Override
    public void add(Integer a, Integer b) {
        System.out.println("a+b=" + (a + b));
    }
}

//測試類
public class TestLambda {
    //測試類中定義了一個方法,並規定了接收參數的類型
    public void test(Example example) {
        example.add(1, 1);
    }
    public static void main(String[] args) {
        //聲明一個接口類型的變量並經過接口實現類實例化
        Example example = new ExampleImpl();
        //main方法中調用本身類的其餘方法必須先建立該類的對象,經過對象調用
        TestLambda testLambda = new TestLambda();
        //調用test,並把實例好的對象傳給test
        testLambda.test(example);    
    }
}

本地運行,控制檯顯示結果爲:a+b=2。固然結果不重要。看懂了上述代碼,思考一下,代碼能否精簡,提升執行效率。
觀察得出:設計模式

  1. 接口的意義好像不是很大,可否去掉,直接定義Example類?呵呵,去掉了咱們後面的研究沒意義了。
  2. 實現類在本例中只用了一次,能否用匿名類替換?——能夠

接下來在上面的代碼基礎上,咱們使用匿名類替換實現類,使得代碼進一步精簡,代碼以下:編程語言

//定義一個接口
interface Example{
    //接口中只定義了一個抽象方法
    void add(Integer a,Integer b);
}
//去掉了接口的實現類

//測試類
public class TestLambda {
    //測試類中定義了一個方法,並規定了接收參數的類型
    public void test(Example example) {
        example.add(1, 1);
    }
    public static void main(String[] args) {
        //main方法中調用本身類的其餘方法必須先建立該類的對象,經過對象調用
        TestLambda testLambda = new TestLambda();
        //調用test,並把Example類型的匿名類對象傳給方法
        testLambda.test(new Example(){        
            @Override
            public void add(Integer a, Integer b) {
                System.out.println("a+b=" + (a + b));
                
            }
        });    
    }
}

使用匿名類,咱們精簡了代碼,還能不能更加精簡呢?
匿名類知足了傳統面向對象的設計模式對函數對象的需求,可是,匿名類的繁瑣使得Java中進行函數編程的前景變得十分黯淡。咱們平時的方法函數如同簡單函數f(x),像這種f(t(x))的複合函數不常見。所謂函數式編程就是將函數(一段操做)做爲一個基本單位進行傳遞。之前的Java中參數只能是具體的變量,函數式編程打破這一規範,能夠將整個方法做爲一個參數傳遞。
下面咱們使用Lambda表達式,進一步精簡代碼:ide

//定義一個接口
interface Example{
    //接口中只定義了一個抽象方法
    void add(Integer a,Integer b);
}
//去掉了接口的實現類

//測試類
public class TestLambda {
    //測試類中定義了一個方法,並規定了接收參數的類型
    public void test(Example example) {
        example.add(1, 1);
    }
    public static void main(String[] args) {
        //main方法中調用本身類的其餘方法必須先建立該類的對象,經過對象調用
        TestLambda testLambda = new TestLambda();
        //調用test,並把Lambda表達式傳給方法
        testLambda.test((a,b)->System.out.println("a+b=" + (a + b)));    
    }
}

Lambda表達式代碼:
(a,b)->System.out.println("a+b=" + (a + b))
最終執行效果同上。這樣咱們經過使用Lambda表達式達到了代碼乾淨簡潔,執行效率高效的目的。函數式編程

三、反思

咱們前後經過匿名類和Lambda表達式對代碼重構,使得代碼精簡,使用匿名類容易理解,可是使用Lambda表達式感受與咱們開頭的共識向左,緣由是什麼呢?這個表達式難道就是符合類型要求的對象?這個表達式到底是如何起做用的?我想你們必定存在不少疑問。
注意觀察:定義的接口只有一個抽象方法。
疑問答案:在Java8中(向後兼容),造成了「帶有單個抽象方法的接口是特殊的,值得特殊對待」的觀念,這些接口被稱爲函數接口,Java容許利用Lambda表達式建立這些接口的實例。Lambda相似於匿名類的函數,可是比它簡潔更多。Lambda表達式被稱爲函數對象。
類型推導:編譯器利用一個被稱爲類型推導的過程,根據上下文推斷出類型。首先代碼案例中,testLambda.test()方法惟一(TestLambda類中沒有重載的test方法),編譯器會強制認爲testLambda.test()方法中的實際參數類型即Lambda表達式類型爲定義的形式參數類型Example,又因爲接口只有一個抽象方法,Lambda表達式天然只能實現該抽象方法,Lambda表達式表達式中的參數類型天然就是接口中抽象方法的參數類型。函數

四、總結

能寫成Lambda的接口的條件:接口中有且僅有一個抽象方法。如本案例中的接口Example,若是出現多個抽象方法,編譯器的類型推導會出錯。測試

函數式接口可使用(不強求)註解@FunctionalInterface 進行強制規範
image.png
更多Lambda語法知識,可參考官方文檔。spa

相關文章
相關標籤/搜索