JAVA8 匿名內部類和lambda表示式
一.匿名內部類
匿名內部類適合建立那種只需要一次使用的類,例如前面介紹命令模式時所需要的Command物件,匿名內部類的語法有點奇怪,建立匿名內部類時會立即建立一個該類的例項,這個類的定義立即消失,匿名內部類不能重複使用。
語法格式一般如下:
new 實現介面() | 父類構造器 (實參列表){
//匿名內部類的類體部分
}
從上面可以看出,匿名內部類必須繼承一個父類,或者實現一個介面,但最多隻能繼承一個父類,或者實現一個介面。
關於匿名內部類還有如下兩條規則:
1.匿名內部類不能是抽象類,因為系統在建立匿名內部類時,會立即建立匿名內部類的物件,因此不允許將匿名內部類定義為抽象類。
2.匿名內部類不能定義構造器(Constructor),由於匿名內部類沒有類名,所以無法定義構造器,但匿名構造類可以定義初始化塊,可以通過例項初始化塊來完成建構函式需要完成的部分。
Example 1:
interface MyInter{ public String getName(); } public class AnonymousTest{ public void test(MyInter i){ System.out.println("The Content of this function is "+i.getName()); }public static void main(String[] args){ AnonymousTest ta; ta.test(new MyInter(){ public String getName(){ return "Anonymous Content"; } }); }
以上的程式碼等價的實現類物件的程式碼是:
class AnonymousEqual implements MyInter{ public String getName(){return "Anonymous Class Content"; } }
Example 2:
abstract class MyUpperClass{ private String name; public abstract String getName(); public MyUpperClass(){} public MyUpperClass(String s){ name=s; } }////Abstract instead of Interface public class AnonymousTest{ public void test(MyUpperClass m){ System.out.println("The Content of This Method is "+m.getName()); } ////////////// public static void main(String[] args){ AnonymousTest at; at.test(new MyUpperClass("Abstract Class Derived Content"){ public String getName(){ return "AnonymousClass Derived Content"; } }); } }
二.Lambda表示式
Lambda表示式是Java8的重要更新,也是一個被廣大開發者期待已久的新特性。Lambda表示式支援將程式碼塊作為引數,Lambda表示式允許使用更簡潔的程式碼來建立只有一個抽象方法的介面(這種介面被稱為函式式介面)的例項。
Lambda表示式完全可以用於簡化建立匿名內部類物件,因此可將上面中的Example 1中的程式碼改寫成如下的形式。
public class AnonymousTest{ public void test(MyInter i){ System.out.println("The Content of This Method is "+i.getName()); } ////////////////// public static void main(String []args){ AnonymousTest at; at.test(()->new String("Lambda Content")); } }
從上面的程式之中可以看出,這段程式碼之中Lambda表示式所實現的test方法和匿名內部類所實現的test方法是完全等價的,只是不再需要一個繁瑣的程式碼塊重新宣告一個匿名類,不需要重新指出所重寫的方法的名字,也不需要給出重寫的方法的返回值型別。
從上面的方法之中可以看出,lambda表示式代替匿名內部類的時候,lambda程式碼塊將會實現代替實現抽象類的方法體,lambda表示式的語法主要由三部分構成:
(1)形參列表,如果只有一個引數可以省略括號,當無引數型別時可以使用()或者obj來代替。
(2)箭頭(->)
(3)程式碼塊部分,如果程式碼只有一行則可以省略掉花括號,不然使用花括號將lambda表示式的程式碼部分標記出來。
Lambda表示式的型別,也被稱為“目標型別(target type)”,lambda表示式的目標型別必須是“函式式介面(functional interface)”。函式式介面代表只包含一個抽象方法的介面。函式式介面可以包含多個預設方法,類方法,但只能宣告一個抽象方法。如果採用匿名型別內部類來建立函式式介面的例項,則只需要實現一個抽象方法,在這種情況下即可採用lambda表示式來建立物件,該表示式創建出來的物件目標就是這個函式介面。(可以用@FunctionalInterface註解來對函式介面實行限制)
##表示式的目標型別必須是明確的函式式介面
##lambda表示式只能為函式式介面建立物件,lambda表示式只能實現一個方法,因此他它只能為只有一個抽象方法的藉口(函式式介面)建立物件。
另外需要注意的一點是: Object不是函式式介面
為了保證lambda表示式的目標型別是一個明確的函式式介面,可以有如下三種常見的方法:
##將lambda表示式賦值給函式式介面型別的變數
##將lambda表示式當作引數傳遞給需要函式式介面型別的引數的呼叫方法
##使用函式式介面對lambda表示式進行強制的型別轉換
附:
在java.util.function包預定下了大量函式式介面,典型的包含如下4類介面。
***Function:這類介面通常包含一個apply抽象方法,對引數進行處理轉換,然後返回一個新的值。
***Consumer:這類介面通常包含一個accept抽象方法,用於對引數進行處理,但是不返回一個新的值。
***Predicate:這類介面通常包含一個test抽象方方法,通過對引數的處理計算,然後返回一個boolean值
***Supplier:這類介面通常包含一個getAs***抽象方法,這種方法無引數,按照某種邏輯運算返回一個數據值。