1. 程式人生 > >JAVA8 匿名內部類和lambda表示式

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***抽象方法,這種方法無引數,按照某種邏輯運算返回一個數據值。