java8 新特性之函式式介面

lixon166發表於2021-01-17

函式式介面介紹(摘自菜鳥):

函式式介面(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的介面。

函式式介面可以被隱式轉換為 lambda 表示式。

Lambda 表示式和方法引用(實際上也可認為是Lambda表示式)上。

如定義了一個函式式介面如下:

@FunctionalInterfaceinterface GreetingService 
{    void sayMessage(String message);
}

那麼就可以使用Lambda表示式來表示該介面的一個實現(注:JAVA 8 之前一般是用匿名類實現的):

GreetingService greetService1 = message -> System.out.println("Hello " + message);

java.util.function 它包含了很多類,用來支援 Java的 函數語言程式設計,該包中的函式式介面有(對於英文不好的我,這個表格也算是照抄下來了):

 

序號 介面 & 描述
1 BiConsumer<T,U>

代表了一個接受兩個輸入引數的操作,並且不返回任何結果

2 BiFunction<T,U,R>

代表了一個接受兩個輸入引數的方法,並且返回一個結果

3 BinaryOperator<T>

代表了一個作用於於兩個同型別運算子的操作,並且返回了運算子同型別的結果

4 BiPredicate<T,U>

代表了一個兩個引數的boolean值方法

5 BooleanSupplier

代表了boolean值結果的提供方

6 Consumer<T>

代表了接受一個輸入引數並且無返回的操作

7 DoubleBinaryOperator

代表了作用於兩個double值運算子的操作,並且返回了一個double值的結果。

8 DoubleConsumer

代表一個接受double值引數的操作,並且不返回結果。

9 DoubleFunction<R>

代表接受一個double值引數的方法,並且返回結果

10 DoublePredicate

代表一個擁有double值引數的boolean值方法

11 DoubleSupplier

代表一個double值結構的提供方

12 DoubleToIntFunction

接受一個double型別輸入,返回一個int型別結果。

13 DoubleToLongFunction

接受一個double型別輸入,返回一個long型別結果

14 DoubleUnaryOperator

接受一個引數同為型別double,返回值型別也為double 。

15 Function<T,R>

接受一個輸入引數,返回一個結果。

16 IntBinaryOperator

接受兩個引數同為型別int,返回值型別也為int 。

17 IntConsumer

接受一個int型別的輸入引數,無返回值 。

18 IntFunction<R>

接受一個int型別輸入引數,返回一個結果 。

19 IntPredicate

:接受一個int輸入引數,返回一個布林值的結果。

20 IntSupplier

無引數,返回一個int型別結果。

21 IntToDoubleFunction

接受一個int型別輸入,返回一個double型別結果 。

22 IntToLongFunction

接受一個int型別輸入,返回一個long型別結果。

23 IntUnaryOperator

接受一個引數同為型別int,返回值型別也為int 。

24 LongBinaryOperator

接受兩個引數同為型別long,返回值型別也為long。

25 LongConsumer

接受一個long型別的輸入引數,無返回值。

26 LongFunction<R>

接受一個long型別輸入引數,返回一個結果。

27 LongPredicate

R接受一個long輸入引數,返回一個布林值型別結果。

28 LongSupplier

無引數,返回一個結果long型別的值。

29 LongToDoubleFunction

接受一個long型別輸入,返回一個double型別結果。

30 LongToIntFunction

接受一個long型別輸入,返回一個int型別結果。

31 LongUnaryOperator

接受一個引數同為型別long,返回值型別也為long。

32 ObjDoubleConsumer<T>

接受一個object型別和一個double型別的輸入引數,無返回值。

33 ObjIntConsumer<T>

接受一個object型別和一個int型別的輸入引數,無返回值。

34 ObjLongConsumer<T>

接受一個object型別和一個long型別的輸入引數,無返回值。

35 Predicate<T>

接受一個輸入引數,返回一個布林值結果。

36 Supplier<T>

無引數,返回一個結果。

37 ToDoubleBiFunction<T,U>

接受兩個輸入引數,返回一個double型別結果

38 ToDoubleFunction<T>

接受一個輸入引數,返回一個double型別結果

39 ToIntBiFunction<T,U>

接受兩個輸入引數,返回一個int型別結果。

40 ToIntFunction<T>

接受一個輸入引數,返回一個int型別結果。

41 ToLongBiFunction<T,U>

接受兩個輸入引數,返回一個long型別結果。

42 ToLongFunction<T>

接受一個輸入引數,返回一個long型別結果。

43 UnaryOperator<T>

接受一個引數為型別T,返回值型別也為T。

 

程式碼示例:

菜鳥教程的示例略

BiConsumer<T,U>

代表了一個接受兩個輸入引數的操作,並且不返回任何結果

// 想不到更好的示例了,就測試一下 BiConsumer  應該一次性單獨邏輯,不依賴的eval2(list, (k,v) -> {System.out.println("傳入的引數1為:"+k + "  傳入的引數2為:"+v);});public static void eval2(List<Integer> list, BiConsumer<Integer,String> biConsumer) {        for(Integer n: list) {biConsumer.accept(n,"pa2");}
    }

輸出結果為:

傳入的引數1為:1  傳入的引數2為:pa2
傳入的引數1為:2  傳入的引數2為:pa2
傳入的引數1為:3  傳入的引數2為:pa2
傳入的引數1為:4  傳入的引數2為:pa2
傳入的引數1為:5  傳入的引數2為:pa2
傳入的引數1為:6  傳入的引數2為:pa2
傳入的引數1為:7  傳入的引數2為:pa2
傳入的引數1為:8  傳入的引數2為:pa2
傳入的引數1為:9  傳入的引數2為:pa2

BinaryOperator<T>

代表了一個作用於於兩個同型別運算子的操作,並且返回了運算子同型別的結果

//  代表了一個作用於於兩個同型別運算子的操作,並且返回了運算子同型別的結果        // 邏輯處理,並返回與引數型別一樣的結果eval3(list, (k,v) -> v+k);public static void eval3(List<Integer> list, BinaryOperator<String> binaryOperator) {        for(Integer n: list) {System.out.println(binaryOperator.apply(String.valueOf(n),"abc"));}
}

這個方法泛型只有一個,卻要傳遞兩個引數。結果如下:

abc1
abc2
abc3
abc4
abc5
abc6
abc7
abc8
abc9

 

BiPredicate<T,U>

代表了一個兩個引數的boolean值方法

// BiPredicate<T,U> 方法介紹:代表了一個兩個引數的boolean值方法// 處理邏輯並返回boolean型別,可穿兩個不同型別引數。eval4(list, (k,v) -> v.length()==k);public static void eval4(List<Integer> list, BiPredicate<Integer,String> biPredicate) {        for(Integer n: list) {System.out.println(biPredicate.test(n,"213"));}
}

這個可以傳入兩個不同的型別進行對比,返回boolean型別。結果如下:

falsefalsetruefalsefalsefalsefalsefalsefalse

BiFunction<T,U,R>

代表了一個接受兩個輸入引數的方法,並且返回一個結果

// BiFunction<T,U,R> 代表了一個接受兩個輸入引數的方法,並且返回一個結果// 三個型別都可自定義,相當於處理兩個引數後返回結果。eval5(list, (k,v) -> v.length()==k);public static void eval5(List<Integer> list, BiFunction<Integer,String,Boolean> biFunction) {     for(Integer n: list) {System.out.println(biFunction.apply(n,"213"));}
}

結果如下:

falsefalsetruefalsefalsefalsefalsefalsefalse

 

程式碼沒有具體含義,只是學習一下,其實只要看幾個大概就能理解這個函式式介面的大概邏輯了。

有一些自帶的函式式介面,除了唯一的一個抽象方法,還有一些預設方法,還是很好的。可以看下原始碼,暫時無業務需求。

 貼上完整的練習程式碼如下:

java8 新特性之函式式介面  FunctionInterface

 

寫完函式式介面,有個疑問函式式介面和抽象類有啥區別?除了介面和函式的區別,還有那些區別。以下摘自知乎,還不是很能說服自己。

在 java 8 之前,介面與其實現類之間的  耦合度 太高了( tightly coupled),當需要為一個介面新增方法時,所有的實現類都必須隨之修改。預設方法解決了這個問題,它可以為介面新增新的方法,而不會破壞已有的介面的實現。這在 lambda 表示式作為 java 8 語言的重要特性而出現之際,為升級舊介面且保持向後相容(backward compatibility)提供了途徑。

  • 介面可以被類多實現(被其他介面多繼承),抽象類只能被單繼承。
  • 介面中沒有  this,沒有建構函式,不能擁有例項欄位(例項變數)或例項方法,無法儲存  狀態state),抽象方法中可以。
  • 抽象類不能在 java 8 的 lambda 表示式中使用。
  • 從設計理念上,介面反映的是  “like-a” 關係,抽象類反映的是  “is-a” 關係。

作者:魔王不造反
連結:
來源:知乎
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
 
就像評論裡面說的,“當需要為一個介面新增方法時,所有的實現類都必須隨之修改”,那就增加新的介面,而不是修改原來的,開閉原則可以瞭解一下。
 
 

摘自菜鳥教程的評論
1、Java 8為函式式介面引入了一個新註解@FunctionalInterface,主要用於 編譯級錯誤檢查,加上該註解,當你寫的介面不符合函式式介面定義的時候,編譯器會報錯。
2、 函式式介面裡允許定義靜態方法

  函式式介面裡是可以包含靜態方法,因為靜態方法不能是抽象方法,是一個已經實現了的方法,所以是符合函式式介面的定義的;

3、 函式式介面裡允許定義 java.lang.Object 裡的 public 方法

      函式式介面裡是可以包含Object裡的public方法,這些方法對於函式式介面來說,不被當成是抽象方法(雖然它們是抽象方法);因為任何一個函式式介面的實現,預設都繼承了 Object 類,包含了來自 java.lang.Object 裡對這些抽象方法的實現;

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69992808/viewspace-2750554/,如需轉載,請註明出處,否則將追究法律責任。

相關文章