一、理論說明
1. 函數式接口的定義
Java 函數式接口是一種特殊的接口,它只包含一個抽象方法(Single Abstract Method, SAM),但可以包含多個默認方法或靜態方法。函數式接口是 Java 8 引入 Lambda 表達式的基礎,通過函數式接口可以將行為作為參數傳遞,實現更簡潔、靈活的代碼。
2. 核心特性
- @FunctionalInterface 注解:可選注解,用于標記接口為函數式接口,編譯器會檢查該接口是否只有一個抽象方法。
- 與 Lambda 表達式的關系:Lambda 表達式是函數式接口的實例,可直接賦值給函數式接口類型的變量。
- 內置函數式接口:Java 8 在?
java.util.function
?包中提供了一系列通用的函數式接口,如?Predicate
、Function
、Consumer
?等。
二、內置函數式接口
Java 8 提供了四大核心函數式接口,覆蓋了常見的函數式編程場景:
1.?Predicate<T>
接收一個參數,返回布爾值,用于判斷條件。
@FunctionalInterface
public interface Predicate<T> {boolean test(T t);
}// 使用示例
Predicate<Integer> isEven = num -> num % 2 == 0;
System.out.println(isEven.test(4)); // 輸出: true
2.?Function<T, R>
接收一個參數,返回另一個類型的結果,用于類型轉換。
@FunctionalInterface
public interface Function<T, R> {R apply(T t);
}// 使用示例
Function<String, Integer> strLength = s -> s.length();
System.out.println(strLength.apply("hello")); // 輸出: 5
3.?Consumer<T>
接收一個參數,不返回結果,用于消費數據。
@FunctionalInterface
public interface Consumer<T> {void accept(T t);
}// 使用示例
Consumer<String> printer = s -> System.out.println(s);
printer.accept("Hello, World!"); // 輸出: Hello, World!
4.?Supplier<T>
不接收參數,返回一個結果,用于提供數據。
@FunctionalInterface
public interface Supplier<T> {T get();
}// 使用示例
Supplier<Double> randomSupplier = () -> Math.random();
System.out.println(randomSupplier.get()); // 輸出隨機數
三、自定義函數式接口
可以通過?@FunctionalInterface
?注解定義自己的函數式接口:
@FunctionalInterface
public interface Calculator {int calculate(int a, int b); // 唯一的抽象方法// 默認方法(非抽象)default void printResult(int result) {System.out.println("計算結果: " + result);}
}// 使用 Lambda 表達式實現
Calculator adder = (a, b) -> a + b;
Calculator subtractor = (a, b) -> a - b;System.out.println(adder.calculate(5, 3)); // 輸出: 8
adder.printResult(10); // 輸出: 計算結果: 10
四、方法引用(Method Reference)
方法引用是 Lambda 表達式的一種簡化形式,用于直接引用已存在的方法。
1. 靜態方法引用
// Lambda 表達式
Function<String, Integer> parseInt = s -> Integer.parseInt(s);// 方法引用
Function<String, Integer> parseIntRef = Integer::parseInt;
2. 實例方法引用
// Lambda 表達式
Consumer<String> printer = s -> System.out.println(s);// 方法引用
Consumer<String> printerRef = System.out::println;
3. 構造方法引用
// Lambda 表達式
Supplier<List<String>> listSupplier = () -> new ArrayList<>();// 方法引用
Supplier<List<String>> listSupplierRef = ArrayList::new;
五、應用實例
1. 集合過濾(Predicate)
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;public class FilterExample {public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);// 過濾偶數List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0) // 使用 Predicate.collect(Collectors.toList());System.out.println(evenNumbers); // 輸出: [2, 4, 6]}
}
2. 數據轉換(Function)
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;public class MapExample {public static void main(String[] args) {List<String> words = Arrays.asList("hello", "world");// 轉換為大寫List<String> upperCaseWords = words.stream().map(String::toUpperCase) // 使用 Function.collect(Collectors.toList());System.out.println(upperCaseWords); // 輸出: [HELLO, WORLD]}
}
3. 事件處理
@FunctionalInterface
public interface ClickListener {void onClick(String event);
}public class Button {private ClickListener listener;public void setOnClickListener(ClickListener listener) {this.listener = listener;}public void simulateClick() {if (listener != null) {listener.onClick("Button clicked");}}
}// 使用 Lambda 表達式處理事件
Button button = new Button();
button.setOnClickListener(event -> System.out.println("處理事件: " + event));
button.simulateClick(); // 輸出: 處理事件: Button clicked
六、面試題
題目:
答案:
七、自我總結
函數式接口是 Java 函數式編程的核心,它結合 Lambda 表達式和方法引用,使代碼更簡潔、更具表現力。關鍵要點包括:
- 定義規則:函數式接口只能有一個抽象方法,但可以包含默認方法和靜態方法。
- 內置接口:
Predicate
、Function
、Consumer
?和?Supplier
?覆蓋了常見場景。 - 方法引用:簡化 Lambda 表達式,提高代碼可讀性。
- 與 Stream API 結合:在集合處理中發揮強大作用。
在實際開發中,函數式接口常用于回調、事件處理、集合操作等場景,能夠有效減少樣板代碼,提升開發效率。但需注意避免過度使用復雜的 Lambda 表達式,保持代碼的可維護性。