一、前言
Java 8 為了擺脫太囉嗦,匿名類別再進化,但其實是為了函數化(Functional),導入函數式程式設計(Functional programming, FP)理念。
數學與電腦科學中,Lambda的概念很早就提出過,直到解決邏輯一致性問題(簡單類型λ演算),才逐漸奠定λ演算在語言學和電腦科學學界擁有一席之地。
λ-演算結合了兩種簡化方式,使得這個語義變得簡單,變為可計算的函數,明確的計算模型。
第一種簡化是不給予函式一個確定名稱,而「匿名」地對待它們。例如,兩數的平方和函式
可以用匿名的形式重新寫為:
第二個簡化是λ演算只使用單一個參數輸入的函式。如果普通函式需要兩個參數,例如
可以重新寫成:
這是稱為柯里化的方法,對於柯里化轉換版的計算方式如下
lambda演算中的所有函式都是匿名的,它們沒有名稱,它們只接受一個輸入變數,柯里化用於實現有多個輸入變數的函式。
目錄
- 一、前言
- 二、完美的過渡至Lambda
- 三、自定義函數化Interface
- 四、Java的規劃:java.util.function
- 五、Consumer Interface
- 六、Supplier Interface
- 七、Function Interface
- 八、Predicate Interface
- 九、方法引用(Method Reference)
二、完美的過渡至Lambda
我們大約已經知道Lambda演算就是函數匿名化且可以處理多個輸入變數,語法定義如下
xxxxxxxxxx
parameter -> expression
(parameter1, parameter2, ...) -> expression
結合程式語言函數內可以處理更複雜的運算(多行),使用大括號
{}
形成一個程式區塊,就可以執行複雜的程序了!
xxxxxxxxxx
(parameter1, parameter2, ...) -> { code block }
可是Java是物件導向,所有的建制單位都是Class(基本型別除外)為主,那要怎麼導入函數化呢?
我們知道Lambda表達式是直接表示一個匿名函數,參數(parameter)與實作方法(expression, code block)都在這個Lambda表示完成。聰明的您應該覺得很熟悉,這不就是覆蓋(Override)一個方法的實作流程!但Lambda沒有名字,覆蓋操作需要實作(implements)或繼承(extends)且要有方法名,等等...,直接使用匿名類別就好了,型別推斷為宣告的型別,可是...沒有方法名...,那還不簡單,推斷的型別如果只有一個方法...,別無選擇,簡單又粗暴!
我們先來看一下常用的Runnable,非常符合導入Lambda:
匿名類別的寫法:
xxxxxxxxxx
public static void anonymousClass(String name) {
Runnable run = new Runnable() {
public void run() {
System.out.println("Hello " + name);
}
};
new Thread(run).start();
}
只留下要實作的參數數量與覆蓋實作方法,調整成Lambda表達式:
xxxxxxxxxx
public static void simpleLambda(String name) {
Runnable run = () -> System.out.println("Hello " + name);
new Thread(run).start();
}
執行看看結果:
xxxxxxxxxx
public static void main(String[] args) {
anonymousClass("Tom");
simpleLambda("Ethan");
}
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
Hello Tom
Hello Ethan
Lambda效果良好,而且不會產生匿名的內部類別(inner class)檔案Lambda17$1.class,Class檔變得很乾淨。
三、自定義函數化Interface
如果只有Lambda還真的不夠看,原生的Java中能夠直接利用的,似乎不多(如果大大知道的可以再跟我說),如Runnable、Callable、Comparable...。所以Java提供新註解
@FunctionalInterface
,讓您可以客製化一個抽象方法(single-abstract-method)的介面(interface)。
使用
@FunctionalInterface
有以下這些好處:
(3.1) 利用註解可告知開發人員此介面是函數介面(功能介面),以下稱為函數介面,裡面只有一個方法需要實作,可搭配Lambda表達式使用。
xxxxxxxxxx
public interface ICustFunctional {
void stillNeedsToBeNamedCorrectly();
default String getInfo() {
return "This is to demonstrate functionality.";
}
}
(3.2) 在規劃階段,已經定義為函數介面,後續在開發維護時,可以讓編譯器直接檢查是否符合函數介面的限制條件,不符合編譯時直接報錯,以符合分析規劃等規範。例如以下的code就會報錯
xxxxxxxxxx
public interface ICustFunctional {
void stillNeedsToBeNamedCorrectly();
void secondAbstractMethod(String str);
default String getInfo() {
return "This is to demonstrate functionality.";
}
}
錯誤訊息:Invalid '@FunctionalInterface' annotation; ICustFunctional is not a functional interface.
規定只能有一個抽象方法,一山不容二虎。


讓我們使用該介面再次操作Lambda看看
xxxxxxxxxx
public static void customExpressionLambda(String outText) {
ICustFunctional doOutput = () -> System.out.println(outText);
doOutput.stillNeedsToBeNamedCorrectly();
}
public static void customBlockCodeLambda(int a, int b) {
ICustFunctional doOutput = () -> {
int resultAdd = a + b;
int resultSub = a - b;
int resultMul = a * b;
int resultDiv = a / b;
int resultRemainder = a % b;
System.out.println("The result of addition is " + resultAdd + ".");
System.out.println("The result of subtraction is " + resultSub + ".");
System.out.println("The result of multiplication is " + resultMul + ".");
System.out.println("The result of division is " + resultDiv + ".");
System.out.println("The result of remainder is " + resultRemainder + ".");
};
doOutput.stillNeedsToBeNamedCorrectly();
}
執行結果:
xxxxxxxxxx
public static void main(String[] args) {
customExpressionLambda("Testing Custom ExpressionLambda.");
customBlockCodeLambda(35, 4);
}
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
Testing Custom ExpressionLambda.
The result of addition is 39.
The result of subtraction is 31.
The result of multiplication is 140.
The result of division is 8.
The result of remainder is 3.
四、Java的規劃:java.util.function
Java團隊已經幫各位想好大多數的情境下要如何使用Lambda,定義許多的函數介面在java.util.function套件中,我們就不用在費盡心思要怎麼規劃與命名,真的是太棒了!
Java17 API 網站(java.util.function)
數字類型:提供dobule, int, long, object等相關操作。
- DoubleBinaryOperator
- DoubleConsumer
- DoubleFunction
- DoublePredicate
- DoubleSupplier
- DoubleToIntFunction
- DoubleToLongFunction
- DoubleUnaryOperator
- IntBinaryOperator
- IntConsumer
- IntFunction<R>
- IntPredicate
- IntSupplier
- IntToDoubleFunction
- IntToLongFunction
- IntUnaryOperator
- LongBinaryOperator
- LongConsumer
- LongFunction<R>
- LongPredicate
- LongSupplier
- LongToDoubleFunction
- LongToIntFunction
- LongUnaryOperator
- ObjDoubleConsumer<T>
- ObjIntConsumer<T>
- ObjLongConsumer<T>
- ToDoubleBiFunction<T,U>
- ToDoubleFunction<T>
- ToIntBiFunction<T,U>
- ToIntFunction<T>
- ToLongBiFunction<T,U>
- ToLongFunction<T>
邏輯處理與控制:
- BiConsumer<T,U>
- BiFunction<T,U,R>
- BinaryOperator<T>
- BiPredicate<T,U>
- BooleanSupplier
- Consumer<T>
- Function<T,R>
- Predicate<T>
- Supplier<T>
- UnaryOperator<T>
命名規則解析如下:
- Consumer: 消費者,接收1個參數,無回傳值。概念與POJO的setter雷同。
- Supplier: 提供者,無法接收參數,回傳1個值。概念與POJO的getter雷同。
-
Function: 函數,接收1個參數,回傳1個值。概念與數學函數雷同,例如
- Predicate: 決策(斷定),接收1個參數,回傳boolean值,決定Yes or No。
- Unary: 單一型別(一元運算),輸入輸出型別相同。
五、Consumer Interface
Java 中的 Consumer 是一個函數介面,它可以接受一個泛型 <T> 類型參數,進行處理後無任何返回值。例如傳入一個字串,印出一個字串。
(5.1) Consumer accept
void accept(T t)
是函數介面的抽象方法,傳入一個任意類型,無回傳值,可以用於 Lambda 表達式和方法參考。
範例:輸出字串
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
consumerAccept();
}
public static void consumerAccept(){
Consumer<String> printConsumer = s -> System.out.println(s);
printConsumer.accept("www.google.com");
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
www.google.com
(5.2) Consumer andThen
default Consumer<T> andThen(Consumer<? super T> after)
是Consumer的預設方法,可以傳入一個 Consumer,傳回處理後的Consumer後的 Consumer ,傳入的 Consumer 不能為 null,否則會得到 NullPointerException。
範例:先輸出字串長度,再輸出字串
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
consumerAndThen();
}
public static void consumerAndThen(){
Consumer<String> lengthConsumer = s -> System.out.println(s.length());
Consumer<String> printConsumer = lengthConsumer.andThen(s->System.out.println(s));
printConsumer.accept("www.google.com");
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
14
www.google.com
(5.3) Iterable forEach
default void forEach(Consumer<? super T> action)
是Iterable的預設方法,傳入一個Consumer,再使用for迴圈一個一個處理。
Iterable原始碼:
xxxxxxxxxx
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
範例:建立一個List,輸出所有元素
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
iterableForEach();
}
public static void iterableForEach() {
List<Integer> list = Arrays.asList(1, 3, 5, 7, 9, 2, 4, 6, 8, 10);
list.forEach(e -> System.out.print(e + ", "));
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
1, 3, 5, 7, 9, 2, 4, 6, 8, 10,
(5.4) 其他與Consumer相關
Interface | Description |
---|---|
BiConsumer<T,U> | 傳入兩個任意型別參數,無回傳值 |
DoubleConsumer | 傳入一個 double 參數,無回傳值 |
IntConsumer | 傳入一個 int 參數,無回傳值 |
LongConsumer | 傳入一個 long 參數,無回傳值 |
ObjDoubleConsumer<T> | 傳入一個任意型別參數,一個 double 參數,無回傳值 |
ObjIntConsumer<T> | 傳入一個任意型別參數,一個 int 參數,無回傳值 |
ObjLongConsumer<T> | 傳入一個任意型別參數,一個 long 參數,無回傳值 |
範例:使用ObjIntConsumer<T>判斷集合中數值大於8的元素輸出出來
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
objIntConsumerAccept();
}
public static void objIntConsumerAccept() {
List<Integer> list = Arrays.asList(1, 3, 5, 7, 9, 2, 4, 6, 8, 10);
ObjIntConsumer<Integer> objIntConsumer = (intObj, intNum) -> {
if (intObj > intNum) {
System.out.println(intObj);
}
};
for (Integer ii : list) {
objIntConsumer.accept(ii, 8);
}
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
9
10
六、Supplier Interface
Java 中的 Supplier 是一個函數介面,無參數,傳回值類型為泛型 T。 Supplier 的使用比較簡單,使用場景也比較單一。
(6.1) Supplier get
T get()
是Supplier的抽象方法,無參數,傳回值類型為泛型 T。可以用此方法取得邏輯、演算法一致的資料或創建實例(Instance)。
範例:連續隨機3個1~6整數,輸出兩次,分別代表兩個玩家
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
supplierGet();
}
public static void supplierGet() {
Supplier<List<Integer>> rnd3Nums = () -> {
List<Integer> temp = new ArrayList<>();
Random ran = new Random();
for (int i = 0; i < 3; i++) {
temp.add(ran.nextInt(6) + 1);
}
return temp;
};
System.out.print("Player1: ");
rnd3Nums.get().forEach(e -> System.out.print(e + ", "));
System.out.println("");
System.out.print("Player2: ");
rnd3Nums.get().forEach(e -> System.out.print(e + ", "));
}
}
輸出結果
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
Player1: 3, 1, 3,
Player2: 2, 1, 4,
(6.2) 其他與Supplier相關
Interface | Description |
---|---|
BooleanSupplier | 無參數,回傳一個布林值。 |
DoubleSupplier | 無參數,回傳一個雙精度浮點數。 |
IntSupplier | 無參數,回傳一個整數。 |
LongSupplier | 無參數,回傳一個長整數。 |
範例:設定一個根號2的值
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
doubleSupplierGetAsDouble();
}
public static void doubleSupplierGetAsDouble() {
DoubleSupplier sqrt2 = () -> {
return 1.414213562373095048801688724209698078569671875376948073176679737990732478462;
};
System.out.println("The square root of 2 is " + sqrt2.getAsDouble());
}
}
輸出結果
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
The square root of 2 is 1.4142135623730951
七、Function Interface
在D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java 中,Function 是一個函數介面,它可以接受一個泛型 T 對象,傳回一個泛型 R 對象,即參數類型和返回類型可以不同。
(7.1) Function apply
R apply(T t)
是 Function 的抽象方法,接受一個泛型 T 對象,傳回一個泛型 R 對象。可針對給予的資料,進行分析、邏輯判斷、資料處理查詢儲存等功能,最後返回值提供使用與參考。
範例:輸入字串 <T> String,傳回字串的大寫形式 <R> String。
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
functionApply();
}
public static void functionApply() {
Function<String, String> toUpperCase = str -> str.toUpperCase();
String result = toUpperCase.apply("www.google.com");
System.out.println(result);
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
WWW.GOOGLE.COM
(7.2) Function andThen
default <V> Function<T,V> andThen(Function<? super R,? extends V> after)
是 Function 的預設方法,傳回一個組合函數,該函數首先將此函數應用於其輸入,然後將 after 函數應用於結果。
範例:輸入一個字串,取得字串的長度,然後乘以2。
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
functionAndThen();
}
public static void functionAndThen() {
Function<String, Integer> lengthFunction = str -> str.length();
Function<Integer, Integer> doubleFunction = length -> length * 2;
Integer doubleLength = lengthFunction.andThen(doubleFunction).apply("www.google.com");
System.out.println(doubleLength);
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
28
(7.3) Function compose
default <V> Function<V,R> compose(Function<? super V,? extends T> before)
是 Function 的一個預設方法,傳回一個組合函數,該函數首先將 before 函數應用於其輸入,然後將此函數應用於結果。順序與andThen相反。
範例:輸入一個字串,取得字串的長度,然後乘以2。
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
functionCompose();
}
public static void functionCompose() {
Function<String, Integer> lengthFunction = str -> str.length();
Function<Integer, Integer> doubleFunction = length -> length * 2;
Integer doubleLength = doubleFunction.compose(lengthFunction).apply("www.google.com");
System.out.println(doubleLength);
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
28
(7.4) Function identity
static <T> Function<T,T> identity()
是 Function 的一個靜態方法,回傳一個Function,其輸出值等於輸入值。常用於數據串接。
範例:
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
functionIdentity();
}
public static void functionIdentity() {
Function<String, String> getParameter = Function.identity();
String result = getParameter.apply("www.google.com");
System.out.println(result);
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
www.google.com
(7.5) 其他與Function相關
Interface | Description |
---|---|
BiFunction<T,U,R> | 輸入2個泛型<T>,<U>參數,回傳1個泛型<R> |
DoubleFunction<R> | 輸入1個double,回傳1個泛型<R> |
DoubleToIntFunction | 輸入1個double,回傳1個int |
DoubleToLongFunction | 輸入1個double,回傳1個long |
IntFunction<R> | 輸入1個int,回傳1個泛型<R> |
IntToDoubleFunction | 輸入1個int,回傳1個double |
IntToLongFunction | 輸入1個int,回傳1個long |
LongFunction<R> | 輸入1個long,回傳1個泛型<R> |
LongToDoubleFunction | 輸入1個long,回傳1個double |
LongToIntFunction | 輸入1個long,回傳1個int |
ToDoubleBiFunction<T,U> | 輸入2個泛型<T>,<U>參數,回傳1個double |
ToDoubleFunction<T> | 輸入1個泛型<T>參數,回傳1個double |
ToIntBiFunction<T,U> | 輸入2個泛型<T>,<U>參數,回傳1個int |
ToIntFunction<T> | 輸入1個泛型<T>參數,回傳1個int |
ToLongBiFunction<T,U> | 輸入2個泛型<T>,<U>參數,回傳1個long |
ToLongFunction<T> | 輸入1個泛型<T>參數,回傳1個long |
八、Predicate Interface
Predicate函數介面,它可以接受一個泛型 <T> 參數,返回值為布林類型元素。
(8.1) Predicate test
boolean test(T t)
是 Predicate 的抽象函數,輸入泛型 <T> 參數,輸出布林值,用於判斷一個參數是否滿足某個條件。
輸出:判斷某個字串是否為空。
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
predicateTest();
}
public static void predicateTest() {
Predicate<String> isEmpty = str -> str.isEmpty();
System.out.println(isEmpty.test(""));
System.out.println(isEmpty.test("www.google.com"));
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
true
false
(8.2) Predicate and
default Predicate<T> and(Predicate<? super T> other)
是 Predicate 的一個預設方法,使用and()方法,可以讓前後兩個Predicate判斷條件同時生效。
範例: 判斷數字大小是否在 5 至 9 之間的數字。
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
predicateAnd();
}
public static void predicateAnd() {
Predicate<Integer> greaterThan5 = number -> number > 5;
Predicate<Integer> lessThan9 = number -> number < 9;
Predicate<Integer> filter = greaterThan5.and(lessThan9);
System.out.println(filter.test(10));
System.out.println(filter.test(6));
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
false
true
(8.3) Predicate negate
default Predicate<T> negate()
是 Predicate 的一個預設方法,傳回一個與指定判斷相反的Predicate。
範例:判斷數字不大於5的數字。
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
predicateNegate();
}
public static void predicateNegate(){
Predicate<Integer> greaterThan5 = number -> number > 5;
Predicate<Integer> notGreaterThan5 = greaterThan5.negate();
System.out.println(notGreaterThan5.test(10));
System.out.println(notGreaterThan5.test(6));
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
false
false
(8.4) Predicate or
default Predicate<T> or(Predicate<? super T> other)
是 Predicate 的一個預設方法,使用or()方法,判斷前後兩個Predicate條件都不成立回傳false,至少一個成立回傳ture。
範例:判斷數字小於等於5,或大於等於9的數字。
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
predicateOr();
}
public static void predicateOr(){
Predicate<Integer> leThan5 = number -> number <= 5;
Predicate<Integer> geThan9 = number -> number >= 9;
Predicate<Integer> filter = leThan5.or(geThan9);
System.out.println(filter.test(10));
System.out.println(filter.test(6));
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\javac Lambda17.java &&D:\jdk\zulu17.54.21-ca-dk17.0.13-win_x64\bin\java Lambda17
true
false
(8.5) Predicate not
static <T> Predicate<T> not(Predicate<? super T> target)
是 Predicate 的一個靜態方法,傳回一個與
傳入Predicate相反的結果。
範例:判斷不小於等於5的數字
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
predicateNot();
}
public static void predicateNot() {
Predicate<Integer> lessEqualThan5 = number -> number <= 5;
Predicate<Integer> notLeThan5 = Predicate.not(lessEqualThan5);
System.out.println(notLeThan5.test(10));
System.out.println(notLeThan5.test(6));
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" && D:\jdk\zulu17.54.21-ca-jdk17.0.13-win_x64\bin\javac Lambda17.java && D:\jdk\zulu17.54.21-ca-jdk17.0.13-win_x64\bin\java Lambda17
true
true
(8.6) Predicate isEqual
static <T> Predicate<T> isEqual(Object targetRef)
是 Predicate 的一個靜態方法,傳回一個Predicate,用來測試Object是否相同,測試條件等同Objects.equals(Object, Object)。
範例:判斷Integer是否相等
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
predicateIsEqual();
}
public static void predicateIsEqual(){
Predicate<Integer> isEqualObj = Predicate.isEqual(Integer.valueOf(3));
System.out.println(isEqualObj.test(Integer.parseInt("3")));
System.out.println(isEqualObj.test(Integer.parseInt("5")));
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" && D:\jdk\zulu17.54.21-ca-jdk17.0.13-win_x64\bin\javac Lambda17.java && D:\jdk\zulu17.54.21-ca-jdk17.0.13-win_x64\bin\java Lambda17
true
false
(8.7) 其他與Predicate相關
Interface | Description |
---|---|
BiPredicate<T,U> | 輸入2個泛型<T>,<U>參數,回傳1個boolean |
DoublePredicate | 輸入1個double,回傳1個boolean |
IntPredicate | 輸入1個int,回傳1個boolean |
LongPredicate | 輸入1個long,回傳1個boolean |
九、方法引用(Method Reference)
方法引用是一種特殊型別的 lambda 表達式。使用雙冒號
::
(double colon)區隔函數(method),例如
System.out::println
。
您可以使用 lambda 表達式來建立匿名方法。然而,有時 lambda 表達式除了呼叫現有方法之外什麼也不做。在這些情況下,透過名稱引用現有方法通常會更清楚。方法引用使您能夠做到這一點;它們是緊湊、易於閱讀的 lambda 表達式,適用於已經有名稱的方法。
(9.1) 靜態方法(Static Method)
xxxxxxxxxx
className::methodName
(9.2) 物件的實例方法(an Instance Method of a Object)
xxxxxxxxxx
instanceName::methodName
(9.3) 建構子(Constructor)
xxxxxxxxxx
className::new
typeName[]::new
範例:
xxxxxxxxxx
public class Lambda17 {
public static void main(String[] args) {
methodReference();
}
public static void methodReference() {
// Static Method Reference
Function<String, Integer> getInt = Integer::valueOf;
System.out.println(getInt.apply("28"));
// an Instance Method of a Object Reference
Consumer<String> showPrint = System.out::println;
showPrint.accept("Nice!");
// Constructor Reference
Supplier<Random> rnd = Random::new;
System.out.println(rnd.get().nextInt(9) + 1);
}
}
輸出結果:
xxxxxxxxxx
[Running] cd "d:\Ethan\workspace\lab\example\text\java-newfeatures\src\" && D:\jdk\zulu17.54.21-ca-jdk17.0.13-win_x64\bin\javac Lambda17.java && D:\jdk\zulu17.54.21-ca-jdk17.0.13-win_x64\bin\java Lambda17
28
Nice!
9
沒有留言:
張貼留言