Function
我們知道Java8的最大特性就是函式式介面。所有標註了@FunctionalInterface註解的介面都是函式式介面,具體來說,所有標註了該註解的介面都將能用在lambda表示式上。
介面介紹
/**
* Represents a function that accepts one argument and produces a result.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #apply(Object)}.
*
* @param <T> the type of the input to the function
* @param <R> the type of the result of the function
*
* @since 1.8
*/
上述描述可知: Function中傳遞的兩個泛型:T,R分別代表 輸入引數型別和返回引數型別。下面將逐個介紹Function中的各個介面:
介面1: 執行具體內容介面
R apply(T t);
例項1:apply使用
// 匿名類的方式實現
Function<Integer, Integer> version1 = new Function<Integer, Integer>() {
@Override
public Integer apply(Integer integer) {
return integer++;
}
};
int result1 = version1.apply(20);
// lamda表示式
Function<Integer, Integer> version2 = integer -> integer++;
int result2 = version1.apply(20);
介面2: compose
該方法是一個預設方法,這個方法接收一個function作為引數,將引數function執行的結果作為引數給呼叫的function,以此來實現兩個function組合的功能。
// compose 方法原始碼
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
例項2:compose使用
public int compute(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
return function1.compose(function2).apply(a);
}
// 呼叫上述方法
test.compute(2, value -> value * 3, value -> value * value)
// 執行結果: 12 (有原始碼可以看出先執行before)
介面3 : andThen
瞭解了compose方法,我們再來看andThen方法就好理解了,聽名字就是“接下來”,andThen方法也是接收一個function作為引數,與compse不同的是,先執行本身的apply方法,將執行的結果作為引數給引數中的function。
public interface Function<T, R> {
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
}
例項3:andThen使用
public int compute2(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
return function1.andThen(function2).apply(a);
}
// 呼叫上述方法
test.compute2(2, value -> value * 3, value -> value * value)
// 執行結果 : 36
反思: 多個引數
Function介面雖然很簡潔,但是由Function原始碼可以看出,他只能傳一個引數,實際使用中肯定不能滿足需求。下面提供幾種思路:
- BiFunction可以傳遞兩個引數(Java8中還提供了其它相似Function)
- 通過封裝類來解決
- void函式還是無法解決
因為引數原因“自帶的Function”函式必然不能滿足業務上覆雜多變的需求,那麼就自定義Function介面吧
@FunctionalInterface
static interface ThiConsumer<T,U,W>{
void accept(T t, U u, W w);
default ThiConsumer<T,U,W> andThen(ThiConsumer<? super T,? super U,? super W> consumer){
return (t, u, w)->{
accept(t, u, w);
consumer.accept(t, u, w);
};
}
}
自此,Function介面介紹完畢。
斷言性介面:Predicate
介面介紹:
/**
* Represents a predicate (boolean-valued function) of one argument.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #test(Object)}.
*
* @param <T> the type of the input to the predicate
*
* @since 1.8
*/
@FunctionalInterface
public interface Predicate<T> {
Predicate是個斷言式介面其引數是<T,boolean>,也就是給一個引數T,返回boolean型別的結果。跟Function一樣,Predicate的具體實現也是根據傳入的lambda表示式來決定的。
原始碼不再具體分析,主要有 test/and/or/negate方法,以及一個靜態方法isEqual,具體使用例項如下:
private static void testPredict() {
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
List<Integer> list = new ArrayList<>();
for (int i : numbers) {
list.add(i);
}
// 三個判斷
Predicate<Integer> p1 = i -> i > 5;
Predicate<Integer> p2 = i -> i < 20;
Predicate<Integer> p3 = i -> i % 2 == 0;
List test = list.stream()
.filter(p1
.and(p2)
// .and(Predicate.isEqual(8))
.and(p3))
.collect(Collectors.toList());
System.out.println(test.toString());
//print:[6, 8, 10, 12, 14]
}
供給性介面:Supplier
介面介紹
/**
* Represents a supplier of results.
*
* <p>There is no requirement that a new or distinct result be returned each
* time the supplier is invoked.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #get()}.
*
* @param <T> the type of results supplied by this supplier
*
* @since 1.8
*/
@FunctionalInterface
public interface Supplier<T>
使用例項:
Supplier supplier = "Hello"::toLowerCase;
System.out.println(supplier);
消費性:Consumer
介面介紹
/**
* Represents an operation that accepts a single input argument and returns no
* result. Unlike most other functional interfaces, {@code Consumer} is expected
* to operate via side-effects.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #accept(Object)}.
*
* @param <T> the type of the input to the operation
*
* @since 1.8
*/
@FunctionalInterface
public interface Consumer<T> {
實際使用
NameInfo info = new NameInfo("abc", 123);
Consumer<NameInfo> consumer = t -> {
String infoString = t.name + t.age;
System.out.println("consumer process:" + infoString);
};
consumer.accept(info);
總結:
本文主要介紹Java8的介面式程式設計,以及jdk中提供的四種函式介面(FunctionalInterface)。Predict/Supplier/Consumer其實是Function的一種變形,所以沒有詳細介紹。
疑問: FunctionalInterface註解是如何和lamada表示式聯絡在一起,函式介面在編譯時又是如何處理的?後面再瞭解下