Java8 中新增加了對于 Lambda 表達式的支持,還添加了 Stream 接口,便于對集合對象功能的增強。能夠極大的簡化代碼的編寫并提高代碼的可讀性,提供的
并發(fā)編程模式能夠充分利用多核計算,而且無需編寫線程相關(guān)的代碼。下面的內(nèi)容將會給出使用新的 Lambda 語法對集合對象進行擴展使用。
什么是函數(shù)式接口?
以最常用的迭代操作來舉例,在 Java8 之前,我們進行迭代一個集合需要這樣做:
List<Integer> numbers = Arrays.asList(100, 200, 300, 400);
for (Integer number : numbers) {
System.out.println(number);
}
升級到 Java8 之后,使用 Lambda 表達式進行迭代:
numbers.forEach(number -> System.out.println(number));
甚至可以進一步簡化代碼:
numbers.forEach(System.out::println);
那么這個 forEach 方法是什么?為什么可以做到這一點呢?查看源碼,發(fā)現(xiàn) forEach 方法是來自 Iterable 接口的一個默認方法。它的源碼如下:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
閱讀源碼不難發(fā)現(xiàn),實際上 forEach 還是通過普通的 for 循環(huán)實現(xiàn)的。只不過它的方法簽名需要傳遞一個 Consumer 接口。我們來看一下這個接口的代碼:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
@FunctionalInterface 注解聲明了該接口是一個函數(shù)式接口,這一類函數(shù)式接口有且僅有一個方法,如果添加多個方法,會出現(xiàn)編譯錯誤。我們將一個 Lambda 表達式
傳遞給方法時,編譯器會將 Lambda 表達式轉(zhuǎn)換成對應接口的匿名實現(xiàn)類。也就是說傳遞給 forEach 方法的是 Consumer 的匿名實現(xiàn)類。為了便于觀察,
我們可以將 Lambda 展開成匿名類的寫法:
List<Integer> numbers = Arrays.asList(100, 200, 300, 400);
Consumer<Integer> consumer = new Consumer<Integer>() {
@Override
public void accept(Integer number) {
System.out.println(number);
}
};
numbers.forEach(consumer);
如何應用函數(shù)式接口?
java.util.function 包中定義了一系列和函數(shù)式編程相關(guān)的類與接口,針對基本數(shù)據(jù)類型的接口有以下幾種:
- Predicate -- 傳入一個參數(shù),返回一個 boolean 結(jié)果, 方法為 `boolean test(T t)``
- Consumer -- 傳入一個參數(shù),無返回值,純消費。 方法為 `void accept(T t)``
- Function -- 傳入一個參數(shù),返回一個結(jié)果,方法為 `R apply(T t)``
- Supplier -- 無參數(shù)傳入,返回一個結(jié)果,方法為
T get() - UnaryOperator -- 一元操作符, 繼承 Function,傳入?yún)?shù)的類型和返回類型相同。
- BinaryOperator -- 二元操作符, 傳入的兩個參數(shù)的類型和返回類型相同,繼承 BiFunction
我們可以使用這些接口實現(xiàn)一些自己的函數(shù)式接口,還是以迭代為例,我們來自己實現(xiàn)一個 forEach 方法:
// 定義一個函數(shù)式接口 MyConsumer,接收一個泛型參數(shù)無返回值
@FunctionalInterface
public interface MyConsumer<T> {
void accept(T t);
}
// 定義一個自己的 forEach 方法,傳入自己定義的函數(shù)式接口和需要迭代的集合
public class Demo {
public static <T> void forEach(MyConsumer<T> consumer, Collection<T> collection) {
for (T t : collection) {
consumer.accept(t);
}
}
}
// 調(diào)用自己的 forEach 方法,打印集合元素
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(100, 200, 300);
Demo.forEach(System.out::println, numbers);
}