Author:Dorae
Date:2017年11月1日23:03:26
轉載請註明出處java
提及Java8,可能不少人都已經知道其最大的改進,就是引入了Lambda表達式與Stream,畢竟Java9都已近發佈了,Java8發佈了也已經近三年。那麼,今天咱們就先來說一下Java8引入的Lambda表達式,以及由此引入的函數式編程,以及函數式接口。編程
函數式編程並非Java新提出的概念,其與指令編程相比,強調函數的計算比指令的計算更重要;與過程化編程相比,其中函數的計算能夠隨時調用。ide
固然,你們應該都知道面向對象的特性(抽象、封裝、繼承、多態)。其實在Java8出現以前,咱們關注的每每是某一類對象應該具備什麼樣的屬性,固然這也是面向對象的核心--對數據進行抽象。可是java8出現之後,這一點開始出現變化,彷佛在某種場景下,更加關注某一類共有的行爲(這彷佛與以前的接口有些相似),這也就是java8提出函數式編程的目的。如圖1-1所示,展現了面向對象編程到面向行爲編程的變化。函數式編程
圖1-1函數
首先,不得不提增長Lambda的目的,其實就是爲了支持函數式編程,而爲了支持Lambda表達式,纔有了函數式接口。另外,爲了在面對大型數據集合時,爲了可以更加高效的開發,編寫的代碼更加易於維護,更加容易運行在多核CPU上,java在語言層面增長了Lambda表達式。spa
前邊廢話了這麼多,其實Lambda就是Java新增的語法而已。固然,Lambda(咱們認爲這裏包含了方法引用)確實可以給咱們的開發帶來許多便利。
首先,在java8以前,若是須要創建一個線程,很大可能會寫出下面的代碼:線程
new Thread(new Runnable()) {
@Override
public void run() {
System.out.println("Hello World!");
}
}).start();
複製代碼
可是Java8引入Lambda以後,也許這樣寫會更好:3d
new Thread(
() -> System.out.println("Hello world!");
);
複製代碼
很明顯,Lambda能夠幫助咱們減小模板代碼的書寫,同時減小了要維護的匿名內部類,固然,其做用毫不僅僅這麼一點(關於Lambda的具體使用,讀者能夠參考java8函數式編程這本書,做者解析的很詳細)。接下來咱們先來看一下java8關於接口的的變更。code
其實Java9中關於接口,又有了進一步的變更,這裏咱們暫且侷限於Java8。在Java8中,接口能夠包含靜態方法,另外還增長了一個用於修飾方法的關鍵字--default,稱之爲默認方法(帶有方法體)。cdn
其實Java8中增長靜態方法,目的徹底出於編寫類庫,對某些行爲進行抽象(還記得咱們以前用類去作嗎?)。可是有一點不一樣的是:類中的靜態方法能夠繼承,而且能夠從實例得到引用(並不建議這麼作);可是接口中的靜態方法不能被繼承。
其實,引入默認方法,是不得已而爲之,由於Java8引入了函數式接口,許多像Collection這樣的基礎接口中增長了方法,若是仍是一個傳統的抽象方法的話,那麼可能不少第三方類庫就會變得徹底沒法使用。爲了實現二進制的向後兼容性,引入了帶有方法體、被default修飾的方法--默認方法。其主要思想就是若是子類中沒有實現,那麼採用父類提供的默認實現。其具體的繼承規則如圖1-2所示。
圖1-2
其中Parent接口中定義了默認方法welcome;
Child接口對默認方法進行了覆蓋;
ParentImpl繼承了Parent接口的方法;
ChildImpl繼承了Child的方法;
OverridingParent覆蓋了父類的welcome; OverridingChild最終的welcome來自於OverridingParent。
關於繼承規則,能夠簡短描述爲:類勝於接口;子類勝於父類;若是前二者都不適用,那麼子類要麼實現該方法,要麼將該方法聲明爲抽象方法。
關於接口的變更,Java8中新定義了一種接口類型,函數式接口,與其餘接口的區別就是:
Java8以前已經存在的函數式接口有:
java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.nio.file.PathMatcher
java.lang.reflect.InvocationHandler
java.beans.PropertyChangeListener
java.awt.event.ActionListener
javax.swing.event.ChangeListener
另外,Java8還提供了@FunctionalInterface註解來幫助咱們標識函數式接口。另外須要注意的是函數式接口的目的是對某一個行爲進行封裝,某些接口可能只是巧合符合函數式接口的定義。
如圖1-3所示,爲java8的Function包的結構(即新引入的函數式接口),圖中綠色表示主要引入的新接口,其餘接口基本上都是爲了支持基本類型而添加的接口,方法的具體做用圖中有具體說明。
圖1-3
看下以下代碼,最終輸出應該是兩行"Hello World!",是否是很神奇?
public class Main {
public static void main(String[] args) {
Action action = System.out :: println;
action.execute("Hello World!");
test(System.out :: println, "Hello World!");
}
static void test(Action action, String str) {
action.execute(str);
}
}
@FunctionalInterface
interface Action<T> {
public void execute(T t);
}
複製代碼
本文對Lambda以及函數式接口進行了簡要介紹,目的是激發你們使用Lambda的興趣,步入函數式編程的大門。