感受Lambda表達式寫起來確實很簡潔,今天就簡單看了一下Lambda表達式。在Java 8,一個重要的變動是引入Lambda表達式(lambda expression
),這聽起來彷佛很牛,有種我雖然不知道Lambda表達式是什麼,但我仍然以爲很厲害的感受。具體到語言層面上Lambda表達式不過是一種新的語法而已,下面就一塊兒敲開Java函數式編程的大門。html
到底什麼是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
//能夠放多行代碼 以 大括號擴起 new Thread( () -> { System.out.println("Thread test111"); System.out.println("Thread test222"); } ).start();
因此,就有以下: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一塊兒使用。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的明顯優點:
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