認識JDK8新特性之Lambda表達式

說來挺慚愧的,JDK8已經出來這麼多年,在實際項目中卻不多真正使用Lambda表達式。其實工做中的項目很早就從開發、測試、生產,全面使用JDK8+Tomcat8了。html

因此看來是時候要從新認識下這個奇怪的東西。java

沒錯,當第一次看到Lambda表達式時,我就認爲這是個奇怪的東西,->寫法讓我感受這是在寫其它語言,說好的一切皆對象呢?oracle

表達式語法

這是Lambda表達式的基本語法:app

(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
    statment1;
    statment2;
    //......
    return statmentM;
}

參數列表是一個逗號分隔的形式參數列表,這些參數與功能接口中單一方法的形式參數相對應。指定參數類型是可選項;若是未指定參數類型,將從上下文推斷。參數列表必須用括號括起來,但當指定的單一參數不帶參數類型時除外;指定單一形式參數時能夠不帶括號。若是功能接口方法不指定任何形式參數,則必須指定空括號。測試

語句塊必須包含在大括號內,除非語句塊是一個方法調用語句。ui

舉個簡單例子

對於無參無返回值,能夠有以下寫法:this

public interface TestIntf {
    public void sayHello();
}

// -> 前的一對小括號和後面的一對大括號都不能去掉。
TestIntf intf = () -> {System.out.println("HelloWorld!!!");};
intf.sayHello();

對於有參有返回值,能夠有以下寫法:code

public interface TestIntf {
    public String sayHello(String word);
}

// 完整寫法
TestIntf intf = (String word) -> {return "Hello " + word;};

// 參數word的類型能夠推斷時,能夠去掉類型定義:
TestIntf intf = (word) -> {return "Hello " + word;};

// 甚至當參數只有一個時,能夠去掉左邊的小括號:
TestIntf intf = word -> {return "Hello " + word;};

// 右側的方法體只有一個表達式時,能夠去掉大括號,甚至連return均可以不要:
TestIntf intf = word -> "Hello " + word;

變量做用域

Lambda表達式內部能夠訪問外部的變量,但須要注意:htm

局部變量不管是在Lambda表達式主體中聲明,仍是在封閉做用域中聲明,使用以前都必須先初始化。如:對象

interface TestIntf {
    public String sayHello(String word);
}

public class App {
    public static void main(String[] args) {
        String str;
        TestIntf intf = (String word) -> {
            System.out.println(str); // 編譯失敗,提示str變量未被初始化。
            return "Hello " + word;
        };
    }
}

Lambda表達式不會定義新的做用域;Lambda表達式的做用域與封閉做用域相同。如:

interface TestIntf {
    public String sayHello(String word);
}

public class App {
    public static void main(String[] args) {
        String str = "word";
        TestIntf intf = (String word) -> {
            String str = ""; // 編譯失敗,提示str變量重複定義了。
            return "Hello " + word;
        };
    }
}

並且也不能修改外部變量:

interface TestIntf {
    public String sayHello(String word);
}

public class App {
    public static void main(String[] args) {
        String str = "word";
        TestIntf intf = (String word) -> {
            str = "word!!!"; // 編譯報錯:Local variable str defined in an enclosing scope must be final or effectively final
            return "Hello " + word;
        };
    }
}

固然,引用變量是能夠經過內部方法達到數據修改的。

interface TestIntf {
    public String sayHello(StringBuilder word);
}

public class App {
    public static void main(String[] args) {
        StringBuilder str = new StringBuilder("word");
        TestIntf intf = (StringBuilder word) -> {
            word.append("!!!");
            return "Hello " + word;
        };
        System.out.println(intf.sayHello(str)); // Hello word!!!
        System.out.println(str); // word!!!
    }
}

Lambda表達式中的this

在Lambda表達式中this引用的不是Lambda表達式對象,而是聲明它的外部對象:

interface TestIntf {
    public String sayHello();
}

public class App {
    
    public void test() {
        TestIntf intf = () -> "Hello " + this.getClass().getSimpleName();
        System.out.println(intf.sayHello());
    }
    
    public static void main(String[] args) {
        App app = new App();
        app.test(); // Hello App
    }
}

參考文章

https://www.oracle.com/techne...

相關文章
相關標籤/搜索