例1 用Lambda表達式實現Runnable接口 java
Java代碼 c++
//Before Java 8: new Thread(new Runnable() { @Override public void run() { System.out.println("Before Java8, too much code for too little to do"); } }).start(); //Java 8 way: new Thread( () -> System.out.println("In Java8, Lambda expression rocks !!") ).start();
輸出:
too much code, for too little to do
Lambda expression rocks !!
這個例子使咱們學到了java8中Lambda表達式的書寫方式:
(參數) -> 表達式
(參數) -> 語句
(參數) -> { 語句 }
例如,若是你的方法只是在控制檯打印信息,則能夠這麼寫: express
Java代碼 編程
() -> System.out.println("Hello Lambda Expressions");
若是你的方法接收兩個參數,那麼: 編程語言
Java代碼 ide
(int even, int odd) -> even + odd
順帶提一句,通常來講在Lambda表達式中要儘可能保持變量的簡潔性。這會使你的代碼簡短而能保持在一行以內。因此像上面的代碼能夠選擇變量名相似a,b或者x,y之類的,比起even和odd來會更好。
例2 用Lambda表達式寫事件監聽程序
要是你用過Swing API,那就少不了事件監聽代碼,這是使用匿名類的經典例子。如今咱們能夠用Lambda表達式來抒寫更好的事件處理代碼。 函數式編程
Java代碼 函數
// Before Java 8: JButton show = new JButton("Show"); show.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Event handling without lambda expression is boring"); } }); // Java 8 way: show.addActionListener((e) -> { System.out.println("Light, Camera, Action !! Lambda expressions Rocks"); });
另一個經常使用匿名類的地方是給Collections.sort()方法提供自定義的Comparator接口實現。這個地方也能夠用Lambda表達式。
例3 用Lambda表達式進行List迭代 測試
Java代碼 code
//Prior Java 8 : List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API"); for (String feature : features) { System.out.println(feature); } //In Java 8: List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API"); features.forEach(n -> System.out.println(n));
// 用java8的方法引用更好,方法引用由::(雙冒號)操做符來完成,看起來像c++中的做用域操做符
Java代碼
features.forEach(System.out::println);
輸出:
Lambdas
Default Method
Stream API
Date and Time API
例4 使用Lambda表達式和函數式接口Predicate
除了提供函數式編程語言級別的支持外,java8同時也新增了一個新的包java.util.function。其中包含了許多類來支持java函數式編程。其中之一是Predicate接口,使用這個接口和lamb表達式就能夠以更少的代碼爲API方法添加更多的動態行爲。
如下是Predicate的使用範例,展現了過濾集合數據的許多共性。
Java代碼
public static void main(args[]){ List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp"); System.out.println("Languages which starts with J :"); filter(languages, (str)->str.startsWith("J")); System.out.println("Languages which ends with a "); filter(languages, (str)->str.endsWith("a")); System.out.println("Print all languages :"); filter(languages, (str)->true); System.out.println("Print no language : "); filter(languages, (str)->false); System.out.println("Print language whose length greater than 4:"); filter(languages, (str)->str.length() > 4); } public static void filter(List names, Predicate condition) { for(String name: names) { if(condition.test(name)) { System.out.println(name + " "); } } }
輸出:
Languages which starts with J :
Java
Languages which ends with a
Java
Scala
Print all languages :
Java
Scala
C++
Haskell
Lisp
Print no language :
Print language whose length greater than 4:
Scala
Haskell
Java代碼
//更佳的方式 public static void filter(List names, Predicate condition) { names.stream().filter((name) -> (condition.test(name))).forEach((name) -> { System.out.println(name + " "); }); }
能夠看到Stream API的filter方法也接受一個Predicate,意味着能夠用內聯代碼直接替換咱們自定義的filter()方法。這就是Lambda表達式的威力所在。除此以外Predicate接口也能夠測試多個條件,將會在下面的例子中加以說明。
例5: Lambda表達式結合Predicate
就像上個例子所說,Predicate容許組合兩個以上的條件,它提供了相似於邏輯與和或的操做and(),or()和xor(),這些方法能夠用來組合傳遞到filter方法中的多個條件。例如爲了獲取全部以J開頭並有四個字符長度的語言,能夠定義兩個單獨的Predicate實例覆蓋每一個條件而後用and方法將他們組合在一塊兒。看例子:
Java代碼
Predicate<String> startsWithJ = (n) -> n.startsWith("J"); Predicate<String> fourLetterLong = (n) -> n.length() == 4; names.stream().filter(startsWithJ.and(fourLetterLong)).forEach((n) -> System.out.print("\nName, which starts with 'J' and four letter long is : " + n));
相似能夠用or或者xor。這個例子也強調了單獨用或者按需組合用Predicate的重要性。簡而言之用Predicate和Lambda表達式的優點你能夠寫的更少作得更多。
例6 Map和Reduce的例子
6.1 Map
在這個例子中,咱們要將costBeforeTax的每一個元素以加上他們的增值稅。傳遞一個Lambda表達式給map方法使之應用於每一個元素,以後在用forEach打印結果。
Java代碼
// Without lambda expressions: List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); for (Integer cost : costBeforeTax) { double price = cost + .12*cost; System.out.println(price); } // With Lambda expression: List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); costBeforeTax.stream().map((cost) -> cost + .12*cost).forEach(System.out::println);
輸出
112.0
224.0
336.0
448.0
560.0
112.0
224.0
336.0
448.0
560.0
6.2 Reduce
還有另一個函數reduce能夠將全部值轉換爲一個值。map跟reduce操做是函數式編程的核心,reduce也被稱做摺疊操做。reduce並非一種新的操做,在SQL中咱們用的一些彙集函數好比sum,avg,count等他們實際上也是reduce操做,由於他們也是將多個值進行操做而後返回一個值。Stream API定義了reduce函數,能夠接受一個Lambda表達式而後組合全部值。Stream類中像IntStream都有內置的方法像average(), count(), sum(), mapToLong(), mapToDouble()等轉換方法。咱們能夠用內置的方法也能夠自定義。
Java代碼
// Old way: List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); double total = 0; for (Integer cost : costBeforeTax) { double price = cost + .12*cost; total = total + price; } System.out.println("Total : " + total); // New way: List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500); double bill = costBeforeTax.stream().map((cost) -> cost + .12*cost).reduce((sum, cost) -> sum + cost).get(); System.out.println("Total : " + bill);
輸出
Total : 1680.0
Total : 1680.0
例7 用filter建立一個字符串List
在java開發中對大的集合進行過濾是經常使用的操做。用Lambda表達式和Stream API會讓操做變得簡單易懂。
Stream提供了一個filter()方法,接受一個Predicate對象。這意味着能夠傳遞一個Lambda表達式做爲過濾邏輯,看例子:
Java代碼
//建立一個長度大於兩個字符的字符串List List<String> filtered = strList.stream().filter(x -> x.length()> 2).collect(Collectors.toList()); System.out.printf("Original List : %s, filtered list : %s %n", strList, filtered);
輸出 :
Original List : [abc, , bcd, , defg, jk], filtered list : [abc, bcd, defg]
例8 給每一個List元素應用函數
在工做中咱們常常會碰到這樣的狀況:給List中每一個元素加以必定的操做例如乘以或者除以某個值等。這些操做用map方法再好不過了,咱們能夠將轉換邏輯以Lambda表達式傳給map方法來應用於每一個元素:
//將字符串轉爲大寫而後用逗號連起來
Java代碼
List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy","U.K.","Canada"); String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", ")); System.out.println(G7Countries);
輸出:
USA, JAPAN, FRANCE, GERMANY, ITALY, U.K., CANADA
例9 複製不一樣值到子列表
本例演示如何利用Stream類的distinct方法過濾重複值到集合中。
Java代碼
List<Integer> numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4); List<Integer> distinct = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList()); System.out.printf("Original List : %s, Square Without duplicates : %s %n", numbers, distinct);
輸出 :
Original List : [9, 10, 3, 4, 7, 3, 4], Square Without duplicates : [81, 100, 9, 16, 49]
例10 計算List中元素的最大,最小,和以及平均值
在Stream類中像IntStream, LongStream and DoubleStream有一個很是有用的方法summaryStattics(),返回IntSummaryStatistics, LongSummaryStatistics or DoubleSummaryStatistics其描述了這個流中元素的統計數據。下面的例子中咱們用這個方法來計算一個List中的最大最小值總和以及均值:
Java代碼
List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29); IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics(); System.out.println("Highest prime number in List : " + stats.getMax()); System.out.println("Lowest prime number in List : " + stats.getMin()); System.out.println("Sum of all prime numbers : " + stats.getSum()); System.out.println("Average of all prime numbers : " + stats.getAverage());
輸出: Highest prime number in List : 29 Lowest prime number in List : 2 Sum of all prime numbers : 129 Average of all prime numbers : 12.9