Like Share Discussion Bookmark Smile

J.J. Huang   2020-04-02   Java Java 8   瀏覽次數:次   DMCA.com Protection Status

Java 8 | 函數式接口

函數式接口(Functional Interface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。
函數式接口可以被隱式轉換為lambda表達式。

Lambda的設計者們為了讓現有的功能與Lambda表達式良好兼容,考慮了很多方法,於是產生了函數接口這個概念。函數接口指的是只有一個函數的接口,這樣的接口可以隱式轉換為Lambda表達式。

java.lang.Runnablejava.util.concurrent.Callable是函數式接口的最佳例子。


函數式接口可以對現有的函數友好地支持lambda

JDK 1.8之前已有的函數式接口:

  • 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

JDK 1.8新增加的函數接口:

java.util.function

註:java.util.function相關的方法,可以直接看官方Documentation


在實踐中,函數式接口非常脆弱:只要某個開發者在該接口中添加一個函數,則該接口就不再是函數式接口進而導致編譯失敗。為了克服這種程式碼層面的脆弱性,並顯式說明某個接口是函數式接口,Java 8提供了一個特殊的註解@FunctionalInterfaceJava庫中的所有相關接口都已經帶有這個註解了),舉個簡單的函數式接口的定義:

1
2
3
4
@FunctionalInterface
public interface Functional {
void method();
}

不過有一點需要注意,默認方法和靜態方法不會破壞函數式接口的定義,因此如下的程式碼是合法的。

1
2
3
4
5
6
7
@FunctionalInterface
public interface FunctionalDefaultMethods {
void method();

default void defaultMethod() {
}
}

函數式接口實例

Predicate <T>接口是一個函數式接口,它接受一個輸入參數T,返回一個布爾值結果。

該接口包含多種默認方法來將Predicate組合成其他復雜的邏輯(比如:與,或,非)。

該接口用於測試對像是truefalse

我們可以通過以下實例(Java8Tester.java)來了解函數式接口Predicate <T>的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
 
public class Java8Tester {
   public static void main(String args[]){
      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        
      // Predicate<Integer> predicate = n -> true
      // n 是一個參數傳遞到 Predicate 接口的 test 方法
      // n 如果存在則 test 方法返回 true
        
      System.out.println("輸出所有資料:");
        
      // 傳遞參數 n
      eval(list, n->true);
        
      // Predicate<Integer> predicate1 = n -> n%2 == 0
      // n 是一個參數傳遞到 Predicate 接口的 test 方法
      // 如果 n%2 為 0 test 方法返回 true
        
      System.out.println("輸出所有偶數:");
      eval(list, n-> n%2 == 0 );
        
      // Predicate<Integer> predicate2 = n -> n > 3
      // n 是一個參數傳遞到 Predicate 接口的 test 方法
      // 如果 n 大於 3 test 方法返回 true
        
      System.out.println("輸出大於 3 的所有數字:");
      eval(list, n-> n > 3 );
   }
    
   public static void eval(List<Integer> list, Predicate<Integer> predicate) {
      for(Integer n: list) {
        
         if(predicate.test(n)) {
            System.out.println(n + " ");
         }
      }
   }
}

輸出的結果為:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
輸出所有資料:
1
2
3
4
5
6
7
8
9
輸出所有偶數:
2
4
6
8
輸出大於 3 的所有數字:
4
5
6
7
8
9

註:以上參考了
Java 8 Lambda新語法,簡化程式,增強效能
Java 8 新特性
Java 8的新特性—终极版
现代化 Java - Java8 指南