Java Lambda入門學習

感受Lambda表達式寫起來確實很簡潔,今天就簡單看了一下Lambda表達式。在Java 8,一個重要的變動是引入Lambda表達式(lambda expression),這聽起來彷佛很牛,有種我雖然不知道Lambda表達式是什麼,但我仍然以爲很厲害的感受。具體到語言層面上Lambda表達式不過是一種新的語法而已,下面就一塊兒敲開Java函數式編程的大門。html

 

Lambda表達式

 

到底什麼是Lambda表達式、什麼是函數式編程。先來看一下Java 8新的語法特性帶來的便利之處,相信你會受益不淺。java

不用Lambda表達式新起一個線程,以下:git

new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread second run test");
            }
        }).start();

Lambda表達式就由能夠這樣寫:github

new Thread(
                () -> System.out.println("Thread first run()")
        ).start();

 

能夠看出,匿名類消失了。可見,lambda expression一個常見的用法是取代(某些)匿名內部類,但Lambda表達式的做用不限於此。web

 

lambda expression表達式的原理

  • Lambda表達式能夠包含多行代碼,須要用大括號把代碼塊括起來,就像寫函數體那樣。如
    //能夠放多行代碼 以 大括號擴起
            new Thread(
                    () -> {
                        System.out.println("Thread test111");
                        System.out.println("Thread test222");
                    }
            ).start();

     

  • Lambda表達式是有類型的,賦值操做的左邊就是類型。Lambda表達式的類型其實是對應接口的類型。
  • Lambda表達式的參數表能夠省略類型,就像代碼2和5那樣。這得益於javac的類型推導機制,編譯器能夠根據上下文推導出類型信息。

因此,就有以下:express

Runnable run = () -> System.out.println("Hello World");
ActionListener listener = event -> System.out.println("test clicked");// 2
Runnable multiLine = () -> {// 3
    System.out.println("Hi ");
    System.out.println("boy");
};
BinaryOperator<Long> add = (Long x, Long y) -> x + y;// 4
BinaryOperator<Long> addImplicit = (x, y) -> x + y;// 5

 

表面上看起來每一個Lambda表達式都是原來匿名內部類的簡寫形式,該內部類實現了某個函數接口(Functional Interface),但事實比這稍微複雜一些,這裏再也不展開。所謂函數接口是指內部只有一個接口函數的接口。Java是強類型語言,不管有沒有顯式指明,每一個變量和對象都必須有明確的類型,沒有顯式指定的時候編譯器會嘗試肯定類型。Lambda表達式的類型就是對應函數接口的類型編程

好比,Runnable的函數式註解以下:api

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

 

 

天作之合-------Lambda和Stream的結合使用

Lambda表達式的另外一個重要用法,是和Stream一塊兒使用。Stream is a sequence of elements supporting sequential and parallel aggregate operations。Stream就是一組元素的序列,支持對這些元素進行各類操做,而這些操做是經過Lambda表達式指定的。能夠把Stream看做Java Collection的一種視圖,就像迭代器是容器的一種視圖那樣(但Stream不會修改容器中的內容)。下面例子展現了Stream的常見用法。oracle

例1:ide

假設須要從一個字符串列表中選出以數字開頭的字符串並輸出,Java 8以前須要這樣寫:

List<String> list = Arrays.asList("1one", "two", "three", "4four");
for(String str : list){
    if(Character.isDigit(str.charAt(0))){
        System.out.println(str);
    }
}

而在Java 8就能夠這樣寫:

strList.stream()// 1.獲得容器的Steam
                .filter(str -> Character.isDigit(str.charAt(0)))// 2.選出以數字開頭的字符串
                .forEach(str -> System.out.println(str));// 3.輸出字符串

上述代碼首先1. 調用List.stream()方法獲得容器的Stream,2. 而後調用filter()方法過濾出以數字開頭的字符串,3. 最後調用forEach()方法輸出結果。

 

例2:

假設須要從一個字符串列表中,選出全部包含own的字符串,將其轉換成大寫形式,並把結果放到新的集合當中。

java8以前的代碼我就不寫了,直接用java8看吧,具體以下:

List<String> testList = Arrays.asList("1owne", "twown", "three", "4fownur");
        Set<String> newList =
                testList.stream()// 1.獲得容器的Stream
                        .filter(str -> str.contains("o"))// 2.選出不以數字開頭的字符串
                        .map(String::toUpperCase)// 3.轉換成大寫形式
                        .collect(Collectors.toSet());// 4.生成結果集

        newList.stream().forEach(str -> System.out.println(str));//5.輸出結果

上述代碼首先
            1. 調用List.stream()方法獲得容器的Stream,
            2. 而後調用filter()方法選出不以數字開頭的字符串,
            3. 以後調用map()方法將字符串轉換成大寫形式,
            4. 最後調用collect()方法將結果轉換成Set。
            5. 用forEach輸出結果。
            例子中還展現了方法引用(method references,代碼中標號3處)以及收集器(Collector,代碼中標號4處)的用法,這裏再也不展開,有興趣能夠自行查資料看看。


經過這個例子咱們看到了Stream鏈式操做,即多個操做能夠連成一串。不用擔憂這會致使對容器的屢次迭代,由於不是每一個Stream的操做都會當即執行。Stream的操做分紅兩類,一類是中間操做(intermediate operations),另外一類是結束操做(terminal operation),只有結束操做纔會致使真正的代碼執行,中間操做只會作一些標記,表示須要對Stream進行某種操做。這意味着能夠在Stream上經過關聯多種操做,但最終只須要一次迭代。

能夠看出,Stream的明顯優點:

  • 減小了模板代碼,只用Lambda表達式指明所需操做,代碼語義更加明確、便於閱讀。
  • 將外部迭代改爲了Stream的內部迭代,方便了JVM自己對迭代過程作優化(好比能夠並行迭代)。

github測試代碼:https://github.com/wangtao1/functional-lambda.git

借閱:

1.https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html 2.http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html 3.https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html

相關文章
相關標籤/搜索