Java-->Lambda表達式

1、函數式接口

函數式接口(functional interface 也叫功能性接口,實際上是同一個東西)。簡單來講,函數式接口是隻包含一個方法的接口。好比Java標準庫中的java.lang.Runnable和 java.util.Comparator都是典型的函數式接口。
java 8提供 @FunctionalInterface做爲註解,這個註解是非必須的,只要接口符合函數式接口的標準(即只包含一個方法的接口),虛擬機會自動判斷, 但 最好在接口上使用註解@FunctionalInterface進行聲明,以避免團隊的其餘人員錯誤地往接口中添加新的方法。java

Java中的lambda沒法單獨出現,它須要一個函數式接口來盛放,lambda表達式方法體其實就是函數接口的實現.express

下面的接口就是一個函數式接口編程

package com.yztcedu.lambdademo_01; @FunctionalInterface //添加此註解後,接口中只能有一個抽象方法。 public interface A { void call(); }

2、lambda語法

包含三部分:
一、一個括號內用逗號分隔的形式參數,參數是函數式接口裏面方法的參數
二、一個箭頭符號:->
三、方法體,能夠是表達式和代碼塊。數據結構

(parameters) -> expression 或者 (parameters) -> { statements; }

經過下面的代碼能夠看到lambda表達式設計的代碼更簡潔,並且可讀性更好。框架

package com.yztcedu.lambdademo_01; public class Demo1 { public static void main(String[] args) { runThreadByLambda(); runThreadByInnerClass(); } public static void runThreadByLambda() { /* Runnable就是一個函數式接口:他只有一個方法run()方法。 一、由於run()方法沒有參數,因此 ->前面的()中不須要聲明形參 二、run返回的是void,因此不須要return。 三、->後面寫的代碼其實就是定義在run方法內的代碼。由於此處代碼只有一行,因此{}也能夠省略。若是此處多與一行,則沒法省略。 */ Runnable runnable = () -> System.out.println("這個是用拉姆達實現的線程"); new Thread(runnable).start(); } public static void runThreadByInnerClass() { Runnable runnable = new Runnable() { @Override public void run() { System.out.println("這個是用內部類實現的線程"); } }; new Thread(runnable).start(); } }

3、方法引用

實際上是lambda表達式的一種簡化寫法。所引用的方法實際上是lambda表達式的方法體實現,語法也很簡單,左邊是容器(能夠是類名,實例名),中間是"::",右邊是相應的方法名。以下所示:ide

ObjectReference::methodName

通常方法的引用格式:函數

  1. 若是是靜態方法,則是ClassName::methodName。如 Object ::equals
  2. 若是是實例方法,則是Instance::methodName。如Object obj=new Object();obj::equals;
  3. 構造函數.則是ClassName::new
package com.yztcedu.lambdademo_01; public class Demo2 { public static void main(String[] args) { /* * 方法引用 */ Runnable runnable = Demo2::run; new Thread(runnable).start(); } public static void run(){ System.out.println("方法引用的代碼..."); } }

能夠看出,doSomething方法就是lambda表達式的實現,這樣的好處就是,若是你以爲lambda的方法體會很長,影響代碼可讀性,方法引用就是個解決辦法大數據

4、默認方法---接口改進

簡單說,就是接口能夠有實現方法,並且不須要實現類去實現其方法。只需在方法名前面加個default關鍵字便可。ui

package com.yztcedu.lambdademo_01; @FunctionalInterface public interface A { void call(); default void fun() { System.out.println("我是接口的默認方法1中的代碼"); } default void fun2() { System.out.println("我是接口的默認方法2中的代碼"); } }

爲何要有這個特性?首先,以前的接口是個雙刃劍,好處是面向抽象而不是面向具體編程,缺陷是,當須要修改接口時候,須要修改所有實現該接口的類,目前的 java 8以前的集合框架沒有foreach方法,一般能想到的解決辦法是在JDK裏給相關的接口添加新的方法及實現。然而,對於已經發布的版本,是無法在給接口 添加新方法的同時不影響已有的實現。因此引進的默認方法。他們的目的是爲了使接口沒有引入與現有的實現不兼容發展。spa

java8中接口和抽象類的區別

形同點:
1.都是抽象類型;
2.均可以有實現方法(之前接口不行);
3.均可以不須要實現類或者繼承者去實現全部方法,(之前不行,如今接口中默認方法不須要實現者實現)

不一樣點
1.抽象類不能夠多重繼承,接口能夠(不管是多重類型繼承仍是多重行爲繼承);
2.抽象類和接口所反映出的設計理念不一樣。其實抽象類表示的是"is-a"關係,接口表示的是"like-a"關係;
3.接口中定義的變量默認是public static final 型,且必須給其初值,因此實現類中不能從新定義,也不能改變其值;抽象類中的變量默認是 default 型,其值能夠在子類中從新定義,也能夠從新賦值。

總結:默認方法給予咱們修改接口而不破壞原來的實現類的結構提供了便利,目前java 8的集合框架已經大量使用了默認方法來改進了,當咱們最終開始使用Java 8的lambdas表達式時,提供給咱們一個平滑的過渡體驗。也許未來咱們會在API設計中看到更多的默認方法的應用。

5、使用lambda改進的集合框架

5.1 集合中內部迭代

package com.yztcedu.lambdademo_01; import java.util.ArrayList; import java.util.List; public class Demo3 { public static void main(String[] args) { List<User> users = new ArrayList<User>(); users.add(new User(20, "張三")); users.add(new User(22, "李四")); users.add(new User(10, "王五")); users.forEach((User user) -> System.out.println(user.getAge())); } }

5.2 Stream API

流(Stream)僅僅表明着數據流,並無數據結構,因此他遍歷完一次以後便再也沒法遍歷(這點在編程時候須要注意,不像Collection,遍歷多少次裏面都還有數據),它的來源能夠是Collection、array、io等等。

流做用是提供了一種操做大數據接口,讓數據操做更容易和更快。它具備過濾、映射以及減小遍歷數等方法,這些方法分兩種:中間方法和終端方法,「流」抽象天生就該是持續的,中間方法永遠返回的是Stream,所以若是咱們要獲取最終結果的話,必須使用終點操做才能收集流產生的最終結果。區分這兩個方法是看他的返回值,若是是Stream則是中間方法,不然是終點方法。

filter

在數據流中實現過濾功能是首先咱們能夠想到的最天然的操做了。Stream接口暴露了一個filter方法,它能夠接受表示操做的Predicate實現來使用定義了過濾條件的lambda表達式。

import java.util.stream.Stream; public class StreamDemo { public static void main(String[] args) { List<User> users = new ArrayList<User>(); users.add(new User(20, "張三")); users.add(new User(22, "李四")); users.add(new User(10, "王五")); Stream<User> stream = users.stream(); stream.filter(p -> p.getAge() > 20); //過濾年齡大於20的 } }

map

假使咱們如今過濾了一些數據,好比轉換對象的時候。Map操做容許咱們執行一個Function的實現(Function<T,R>的泛型T,R分別表示執行輸入和執行結果),它接受入參並返回。

package com.yztcedu.lambdademo_01; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class StreamDemo { public static void main(String[] args) { List<User> users = new ArrayList<User>(); users.add(new User(20, "張三")); users.add(new User(22, "李四")); users.add(new User(10, "王五")); Stream<User> stream = users.stream(); //全部的年齡大於20歲的User對象,轉換爲字符串50對象。如今流中只有字符串對象了。 stream.filter((User user) -> user.getAge() > 20).map((User user) -> {return "50";}); } }

count

count方法是一個流的終點方法,可以使流的結果最終統計,返回long

package com.yztcedu.lambdademo_01; import java.util.ArrayList; import java.util.List; import java.util.stream.Collector; import java.util.stream.Stream; public class StreamDemo { public static void main(String[] args) { List<User> users = new ArrayList<User>(); users.add(new User(20, "張三")); users.add(new User(22, "李四")); users.add(new User(10, "王五")); Stream<User> stream = users.stream(); long count = stream.filter((User user) -> user.getAge() >= 20).map((User user) -> {return "50";}) .count(); //返回流中元素的個數。 System.out.println(count); } }
相關文章
相關標籤/搜索