1. 程式人生 > >JDK1.8新特性(二)Lambda表示式入門

JDK1.8新特性(二)Lambda表示式入門

lambda表示式本質是匿名方法,下面是一些lambda表示式:

(int x, int y) -> x + y

() -> 42

(String s) -> { System.out.println(s); }

第一個lambda表示式接收x和y這兩個整形引數並返回它們的和;
第二個lambda表示式不接收引數,返回整數42;
第三個lambda表示式接收一個字串並把它列印到控制檯,不返回值。

lambda表示式的語法由引數列表、箭頭符號->和函式體組成。函式體既可以是一個表示式,也可以是一個語句塊:
表示式:表示式會被執行然後返回執行結果。
語句塊:語句塊中的語句會被依次執行,就像方法中的語句一樣。
return語句會把控制權交給匿名方法的呼叫者
break和continue只能在迴圈中使用

如果函式體有返回值,那麼函式體內部的每一條路徑都必須返回值

java8的安裝

工欲善其器必先利其器,首先安裝JDK8。過程省略,大家應該都可以自己搞定。但是有一點這裡強調一下(Windows系統):目前我們工作的版本一般是Java 6或者java 7,所以很多人安裝java8基本都是學習為主。這樣就在自己的機器上會存在多版本的JDK。而且大家一般是希望在命令列中執行java命令是基於老版本的jdk。但是在安裝完jdk8並且沒有設定path的情況下,你如果在命令列中輸入:java -version,螢幕上會顯示是jdk 8。這是因為jdk8安裝的時候,會預設在C:/Windows/System32中增加java.exe,這個呼叫的優先順序比path設定要高。所以即使path裡指定是老版本的jdk,但是執行java命令顯示的依然是新版本的jdk。這裡我們要做的就是刪除C:/Windows/System32中的java.exe檔案(不要手抖!)。


Lambda表示式是Java SE 8中一個重要的新特性。lambda表示式允許你通過表示式來代替功能介面。 lambda表示式就和方法一樣,它提供了一個正常的引數列表和一個使用這些引數的主體(body,可以是一個表示式或一個程式碼塊)。
Lambda表示式還增強了集合庫。 Java SE 8添加了2個對集合資料進行批量操作的包: java.util.function 包以及java.util.stream 包。 流(stream)就如同迭代器(iterator),但附加了許多額外的功能。 總的來說,lambda表示式和 stream 是自Java語言新增泛型(Generics)和註解(annotation)以來最大的變化。 在本文中,我們將從簡單到複雜的示例中見認識lambda表示式和stream的強悍。


環境準備
如果還沒有安裝Java 8,那麼你應該先安裝才能使用lambda和stream(譯者建議在虛擬機器中安裝,測試使用)。 像NetBeans 和IntelliJ IDEA 一類的工具和IDE就支援Java 8特性,包括lambda表示式,可重複的註解,緊湊的概要檔案和其他特性。
下面是Java SE 8和NetBeans IDE 8的下載連結:
: 從Oracle下載Java 8,也可以和NetBeans IDE一起下載
NetBeans IDE 8: 從NetBeans官網下載NetBeans IDE
Lambda表示式的語法
基本語法:
(parameters) -> expression

(parameters) ->{ statements; }

下面是Java lambda表示式的簡單例子:

  1. // 1. 不需要引數,返回值為 5
  2. () -> 5
  3. // 2. 接收一個引數(數字型別),返回其2倍的值
  4. x -> 2 * x  
  5. // 3. 接受2個引數(數字),並返回他們的差值
  6. (x, y) -> x – y  
  7. // 4. 接收2個int型整數,返回他們的和
  8. (int x, int y) -> x + y  
  9. // 5. 接受一個 string 物件,並在控制檯列印,不返回任何值(看起來像是返回void)
  10. (String s) -> System.out.print(s)  
基本的Lambda例子
現在,我們已經知道什麼是lambda表示式,讓我們先從一些基本的例子開始。 在本節中,我們將看到lambda表示式如何影響我們編碼的方式。 假設有一個玩家List ,程式設計師可以使用 for 語句 ("for 迴圈")來遍歷,在Java SE 8中可以轉換為另一種形式:
  1. String[] atp = {"Rafael Nadal""Novak Djokovic",  
  2.        "Stanislas Wawrinka",  
  3.        "David Ferrer","Roger Federer",  
  4.        "Andy Murray","Tomas Berdych",  
  5.        "Juan Martin Del Potro"};  
  6. List<String> players =  Arrays.asList(atp);  
  7. // 以前的迴圈方式
  8. for (String player : players) {  
  9.      System.out.print(player + "; ");  
  10. }  
  11. // 使用 lambda 表示式以及函式操作(functional operation)
  12. players.forEach((player) -> System.out.print(player + "; "));  
  13. // 在 Java 8 中使用雙冒號操作符(double colon operator)
  14. players.forEach(System.out::println);  
正如您看到的,lambda表示式可以將我們的程式碼縮減到一行。 另一個例子是在圖形使用者介面程式中,匿名類可以使用lambda表示式來代替。 同樣,在實現Runnable介面時也可以這樣使用:
  1. // 使用匿名內部類
  2. btn.setOnAction(new EventHandler<ActionEvent>() {  
  3.           @Override
  4.           publicvoid handle(ActionEvent event) {  
  5.               System.out.println("Hello World!");   
  6.           }  
  7.     });  
  8. // 或者使用 lambda expression
  9. btn.setOnAction(event -> System.out.println("Hello World!"));  
下面是使用lambdas 來實現 Runnable介面 的示例:
  1. // 1.1使用匿名內部類
  2. new Thread(new Runnable() {  
  3.     @Override
  4.     publicvoid run() {  
  5.         System.out.println("Hello world !");  
  6.     }  
  7. }).start();  
  8. // 1.2使用 lambda expression
  9. new Thread(() -> System.out.println("Hello world !")).start();  
  10. // 2.1使用匿名內部類
  11. Runnable race1 = new Runnable() {  
  12.     @Override
  13.     publicvoid run() {  
  14.         System.out.println("Hello world !");  
  15.     }  
  16. };  
  17. // 2.2使用 lambda expression
  18. Runnable race2 = () -> System.out.println("Hello world !");  
  19. // 直接呼叫 run 方法(沒開新執行緒哦!)
  20. race1.run();  
  21. race2.run();  

Runnable 的 lambda表示式,使用塊格式,將五行程式碼轉換成單行語句。 接下來,在下一節中我們將使用lambdas對集合進行排序。
使用Lambdas排序集合
在Java中,Comparator 類被用來排序集合。 在下面的例子中,我們將根據球員的 name, surname, name 長度 以及最後一個字母。 和前面的示例一樣,先使用匿名內部類來排序,然後再使用lambda表示式精簡我們的程式碼。
在第一個例子中,我們將根據name來排序list。 使用舊的方式,程式碼如下所示:
  1. String[] players = {"Rafael Nadal""Novak Djokovic",   
  2.     "Stanislas Wawrinka""David Ferrer",  
  3.     "Roger Federer""Andy Murray",  
  4.     "Tomas Berdych""Juan Martin Del Potro",  
  5.     "Richard Gasquet""John Isner"};  
  6. // 1.1 使用匿名內部類根據 name 排序 players
  7. Arrays.sort(players, new Comparator<String>() {  
  8.     @Override
  9.     publicint compare(String s1, String s2) {  
  10.         return (s1.compareTo(s2));  
  11.     }  
  12. });  
使用lambdas,可以通過下面的程式碼實現同樣的功能:
  1. // 1.2 使用 lambda expression 排序 players
  2. Comparator<String> sortByName = (String s1, String s2) -> (s1.compareTo(s2));  
  3. Arrays.sort(players, sortByName);  
  4. // 1.3 也可以採用如下形式:
  5. Arrays.sort(players, (String s1, String s2) -> (s1.compareTo(s2)));  

其他的排序如下所示。 和上面的示例一樣,程式碼分別通過匿名內部類和一些lambda表示式來實現Comparator :
  1. // 1.1 使用匿名內部類根據 surname 排序 players
  2. Arrays.sort(players, new Comparator<String>() {  
  3.     @Override
  4.     publicint compare(String s1, String s2) {  
  5.         return (s1.substring(s1.indexOf(" ")).compareTo(s2.substring(s2.indexOf(" "))));  
  6.     }  
  7. });  
  8. // 1.2 使用 lambda expression 排序,根據 surname
  9. Comparator<String> sortBySurname = (String s1, String s2) ->   
  10.     ( s1.substring(s1.indexOf(" ")).compareTo( s2.substring(s2.indexOf(" ")) ) );  
  11. Arrays.sort(players, sortBySurname);  
  12. // 1.3 或者這樣,懷疑原作者是不是想錯了,括號好多...
  13. Arrays.sort(players, (String s1, String s2) ->   
  14.