Java 8
新增的lambda
表達式毫無疑問是使人很是激動的,今後咱們能夠很是簡潔的定義和使用代碼塊而不是用繁瑣的匿名內部類來實現。而接口是lambda
表達式的基礎,要理解lambda
表達式就要先理解接口的概念。java
在Java
中接口是對類行爲的抽象。彷佛繼承也能作到這件事,它們的區別在於Java
中類只能有一個父類,而接口是能夠實現多個的。因此接口更傾向於類的一部分抽象,也就是行爲的抽象,而不是類自己的抽象。編程
要定義一個接口很簡單,使用關鍵字interface
後面再跟上接口名稱就能夠了。類能夠用implements
關鍵字來實現接口。安全
public interface A { void test(); }
public static final
public
Java 8
之後還能夠聲明靜態方法和默認方法// Java 8版本 public interface A { //常量 String AUTHOR = "Yuicon"; //抽象方法 void test(); //默認方法 default void testDefault(){} //靜態方法 static void testStatic(){} }
若是一個類實現的接口中有簽名相同的默認方法,那麼就會有衝突的問題。在Java
中解決這個問題有一些明確的規則:閉包
lambda
表達式是一個可傳遞的代碼塊,能夠在之後執行一次或屢次。之因此會有這麼一個特性,是由於原先在Java中傳遞一個代碼塊是很是繁瑣的一件事情,必需要構建一個對象。好比經常使用的Runnable接口:併發
Runnable runnable = new Runnable() { @Override public void run() { System.out.println("我好麻煩"); } };
lambda
版本就很是簡潔:編程語言
Runnable runnable = () -> System.out.println("我很簡潔");
是的,lambda
版本只要一行就完成了任務。ide
在我看來lambda
表達式是一種語法糖,它提供了一種簡潔、易懂的方式來實現只有一個抽象方法的接口。關鍵詞是隻有一個抽象方法的接口,好比這樣一個接口:函數
@FunctionalInterface public interface A { void test(); } A a = () -> System.out.println("test"); a.test();
其中@FunctionalInterface
註解是用來標記接口爲函數式接口,去掉也不會影響功能,添加了這個註解後編譯器會檢查接口內是否只有一個抽象方法。ui
lambda
表達式主要有如下要素:this
lambda
表達式的參數和普通方法的參數並沒有太大區別,主要的區別點有:
Consumer<String> consumer = s -> System.out.println(s);
lambda
表達式的方法體內只有一條語句的時候,能夠不加大括號且無需指定返回值,編譯器會自動推導。方法體內有多條語句的時候就須要加大括號並手動指定返回值,不過lambda
表達式是沒有本身的做用域的,這點須要注意。
Supplier<String> supplier = () -> { String s = "test"; return s; };
自由變量是指非參數並且不在方法體內定義的變量,咱們來看一個例子:
public static void main(String[] args) { String test = "test"; A a = () -> System.out.println(test); a.test(); }
例子中的變量test
就是一個自由變量,代碼塊a
引用了外部方法的變量,這就是一個閉包了。lambda
表達式會複製一份自由變量的值,對象的話就是複製一個引用,所以lambda
表達式離開了原做用域也能正常使用自由變量。不過lambda
表達式對自由變量是有要求的,自由變量必須是不可變的,緣由是併發執行時不安全。如下代碼是錯誤的:
for (int i = 0; i < 9; i++) { // error A a = () -> System.out.println(i); }
方法引用是語法糖的語法糖,顧名思義方法引用是引用已有方法的一個特性。它的形式以下:
@FunctionalInterface public interface A { void test(String s); } A a = System.out::println; a.test("test");
之因此說方法引用是語法糖的語法糖是由於A a = System.out::println;
徹底等價於A a = s -> System.out.println(s);
,方法引用有5種狀況:
前4種狀況和lambda
表達式是徹底等價的,第5種狀況比較特殊,第一個參數會成爲方法的目標。好比String::compareToIgnoreCase
等同於 (x, y)-> x.compareToIgnoreCase(y)
。
構造器引用是引用對象的構造器,用的是特殊的方法名new
,使用形式爲Object::new
,使用方法和方法引用差很少。
JDK
已經提供了經常使用的函數式接口基本上是不須要本身寫函數式接口的。
一週一篇是不可能一週一篇的,人懶起來就和鹹魚同樣根本不會動彈。還好人是會變通的,上週少了這周補上不就好了!Java
被人詬病繁瑣不是一天兩天了,在各類新生編程語言的追趕下Java
也要加快本身的演進了,更改發佈週期就是一個很好的信號。
參考資料:《Java核心技術 卷1》