簡介
在函式式編程中函式可以在程式中傳來傳去,甚至數字也可以用函式表示,而在面向物件中必須將這些函式封裝成方法,通過呼叫方法實作,所以 Java 從鄰居那拿來了 Lambda,
Java8 引入了 Lambda 運算式,它使代碼變得更簡潔和高效,更方便的讓我們在計算機上說話,長得就像下面那樣,
s -> s + s;
(s1, s2) -> { return s1 + s2; };
Lambda可以用于實作只有一個抽象方法的介面,在介面加上 @FunctionalInterface 注解可以提醒我們介面只有一個抽象方法 ,下面是 Java 的 Comparator 兩種實作方式,以前的寫法是實作一個匿名類,
//comparator2 更簡潔
Comparator<String> comparator1 = (s1, s2) -> s1.compareTo(s2);
Comparator<String> comparator2 = String::compareTo;
幾種常見函式
Java 本身提供了 Function、BiFunction、Predicate、Consumer、Supplier 等幾種函式,介紹如下,
| 函式 | 格式 | 說明 |
|---|---|---|
| Function | Function<T, R> | 接收一個引數,有一個回傳值 |
| BiFunction | BiFunction<T, U, R> | 接收兩個引數,有一個回傳值 |
| Predicate | Predicate<T> | 接收一個引數,回傳值boolean型別 |
| Consumer | Consumer<T> | 接收一個引數,沒有回傳值 |
| Supplier | Supplier<T> | 沒有引數,有一個回傳值 |
Function
Function<T, R> 中 T 是傳入引數的型別,R 是回傳值的型別,原始碼中主要有 apply、compose、andThen 方法,
@FunctionalInterface
public interface Function<T, R> {
//執行函式
R apply(T t);
//先執行 before 函式,再執行當前函式,
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
//先執行當前函式,再執行 after 函式
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
}
示例如下,
Function<Integer, String> fun1 = integer -> String.valueOf(integer + integer);
Function<String, BigDecimal> fun2 = s -> new BigDecimal(s + ".5");
//執行函式
String s = fun1.apply(1);
//兩個函式中都是 fun1 先執行
BigDecimal decimal1 = fun1.andThen(fun2).apply(1);
BigDecimal decimal2 = fun2.compose(fun1).apply(1);
執行后 s 值是 2,decimal1 和 decimal2 值是 2.5,
BiFunction
BiFunction<T, U, R> 中 T 和 U 是傳入的引數型別,R 是回傳值型別,原始碼中有 apply、andThen 方法,因為 BiFunction 需要兩個引數,所以沒有 compose 方法,
@FunctionalInterface
public interface BiFunction<T, U, R> {
//執行方法
R apply(T t, U u);
//先執行當前函式,再執行 after 函式
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t, U u) -> after.apply(apply(t, u));
}
}
示例如下,
BiFunction<Integer, Integer, String> biFunction = (param1, param2) -> String.valueOf(param1 * param2 + 1);
Function<String, BigDecimal> fun1 = s -> new BigDecimal(s + ".5");
//先執行 biFunction,再執行 fun1
BigDecimal decimal3 = biFunction.andThen(fun1).apply(1, 2);
Predicate
Predicate<T> 中 T 是 傳入引數的型別,回傳一個 boolean 型別的值,原始碼中主要有 test、and、negate、or、isEqual 方法,
@FunctionalInterface
public interface Predicate<T> {
//執行方法
boolean test(T t);
//關系運算子 &&,當 test 的結果為 false 時直接結束,不運算 other
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
//關系運算子 !
default Predicate<T> negate() {
return (t) -> !test(t);
}
//關系運算子 ||,當 test 的結果為 true 時直接結束,不運算 other
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
//判斷相等
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
示例如下,
//為慷訓傳 true
Predicate<String> isNull = Objects::isNull;
//不為慷訓傳 true
Predicate<String> nonNull = Objects::nonNull;
boolean bool = isNull.or(nonNull.negate()).and(Predicate.isEqual("123")).test("123");
執行后 bool 的值為 false,執行后 isNull.test() 為 false,nonNull.negate() 為 false,因為最后一個是 and,所以不需要判斷 Predicate.isEqual("123"),最后得出 false || false 為 false,如果 and 之后還有 or 的話要接著判斷,
Consumer
Consumer<T> 中 T 是傳入引數的型別,沒有回傳值,原始碼中有 accept 和 andThen 方法,
@FunctionalInterface
public interface Consumer<T> {
//執行方法
void accept(T t);
//先執行當前函式,再執行 after 函式
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
示例如下,
Consumer<Integer> consumer1 = integer -> System.out.println(integer + 1);
Consumer<Integer> consumer2 = integer -> System.out.println(integer + 2);
//先執行 consumer1,再執行 consumer2
consumer1.andThen(consumer2).accept(1);
執行后控制臺依次列印 2 和 3,
Supplier
Supplier<T> 中 T 是回傳值的型別,沒有傳入的引數,原始碼中只有 get 方法,
@FunctionalInterface
public interface Supplier<T> {
//執行方法
T get();
}
示例如下,
Supplier<LocalDate> supplier = LocalDate::now;
//回傳當前日期
LocalDate localDate = supplier.get();
System.out.println(localDate);
控制臺列印當前日期時間 2020-05-31,
總結
本文對 Java8 中的 lambda 做了簡單了解,介紹了 5 種函式,想熟練使用還需要實踐(第一次寫博客,有不足還請指正),
參考資料
深入淺出 Java 8 Lambda 運算式
Execution in the Kingdom of Nouns
函式式編程中的重要概念
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/177268.html
標籤:Java
