【Java】函数式编程
1 函數(shù)式接口
1.1 概念
函數(shù)式接口是有且僅有一個(gè)抽象方法的接口,可以包括靜態(tài)和默認(rèn)方法。
@FunctionalInterface:加上注解,檢測(cè)是否的函數(shù)式接口
@FunctionalInterface public interface MyFunctionInterface {public abstract void method();static void method2() {}default void method3() {} }1.2 函數(shù)式接口的使用
一般可以作為方法的參數(shù)和返回值類(lèi)型
public static void show(MyFunctionInterface myInter){myInter.method();}public static void main(String[] args) {show(new MyFunctionInterface() {@Overridepublic void method() {System.out.println("使用匿名內(nèi)部類(lèi)重寫(xiě)接口中的抽象方法");}});show(()->{System.out.println("使用lambda表達(dá)式重寫(xiě)接口的抽象方法");});show(()-> System.out.println("使用簡(jiǎn)化lambda表達(dá)式重寫(xiě)接口的抽象方法"));}2 函數(shù)式編程
2.1 性能浪費(fèi)案例
public static void showLog(int level, String message){if(level==1){System.out.println(message);}}public static void main(String[] args) {String msg1 = "Hello";String msg2 = "Hello";String msg3 = "Hello";showLog(1,msg1+msg2+msg3);}調(diào)用showLog方法,第二個(gè)參數(shù)式拼接后的字符串,如果等級(jí)不是1,message不需要輸出,存在浪費(fèi)。
2.2 Lambda優(yōu)化案例
@FunctionalInterface public interface MessageBuider {String buiderMessage(); } public static void showLog(int level, MessageBuider mb){if(level==1){System.out.println(mb.buiderMessage());;}}public static void main(String[] args) {String m1 = "Hello";String m2 = "Zhangsan";showLog(1, ()->{return m1+m2;});}這里只有滿足條件才會(huì)調(diào)用接口的方法進(jìn)行字符串拼接。如果不滿足就不會(huì)進(jìn)行字符串拼接,沒(méi)有了性能的浪費(fèi)。
2.3 使用Lambda作為參數(shù)和返回值
作為參數(shù)
//Runnable是一個(gè)函數(shù)式接口public static void startThread(Runnable run){new Thread(run).start();}public static void main(String[] args) {startThread(()->System.out.println("開(kāi)啟線程"+Thread.currentThread().getName()));}作為返回值
//Comparator是一個(gè)函數(shù)式接口public static Comparator<String> getComparator(){return (o1, o2) -> o2.length()-o1.length();}public static void main(String[] args) {String[] arr = {"aaa","bbbbb","cccccc"};Arrays.sort(arr);System.out.println(Arrays.toString(arr));//[aaa, bbbbb, cccccc]Arrays.sort(arr,getComparator());System.out.println(Arrays.toString(arr));//[cccccc, bbbbb, aaa]}3 常用的函數(shù)式接口
3.1 Supplier接口
僅包含一個(gè)無(wú)參方法:T get()
用來(lái)獲取一個(gè)泛型參數(shù)指定類(lèi)型的對(duì)象數(shù)據(jù)。由于這是一個(gè)函數(shù)式接口,這也就意味著對(duì)應(yīng)的Lambda表達(dá)式需要“對(duì)外提供”一個(gè)符合泛型類(lèi)型的對(duì)象數(shù)據(jù)。
練習(xí):應(yīng)用Supplier求數(shù)組最大值
public static int getMax(Supplier<Integer> sup){return sup.get();}public static void main(String[] args) {int[] arr = {5,6,2,4,1,7,3};int ans = getMax(() -> {int max = arr[0];for (int i : arr) {if (i > max) {max = i;}}return max;});System.out.println(Arrays.toString(arr));//[5, 6, 2, 4, 1, 7, 3]System.out.println(ans);//7}3.2 Consumer接口
consumer接口是一個(gè)消費(fèi)型接口,泛型執(zhí)行什么類(lèi)型,可以使用accept方法消費(fèi)什么類(lèi)型的數(shù)據(jù),至于怎么消費(fèi),需要自定義。
public static void method(String name, Consumer<String> con){con.accept(name);}public static void main(String[] args) {//消費(fèi)方式:輸出method("張三", (name)->{System.out.println(name);});//可以替換為method("張三", System.out::println);//消費(fèi)方式:反轉(zhuǎn)輸出method("張三",(name)->{System.out.println(new StringBuilder(name).reverse().toString());});}默認(rèn)方法andThen:如果一個(gè)方法的參數(shù)和返回值全都是Consumer 類(lèi)型,那么就可以實(shí)現(xiàn)效果:消費(fèi)數(shù)據(jù)的時(shí)候,首先做一個(gè)操作,然后再做一個(gè)操作,實(shí)現(xiàn)組合。而這個(gè)方法就是Consumer 接口中的default方法andThen
default Consumer<T> andThen(Consumer<? super T> after) {Objects.requireNonNull(after);return (T t) ‐> { accept(t); after.accept(t); }; }備注: java.util.Objects 的requireNonNull 靜態(tài)方法將會(huì)在參數(shù)為null時(shí)主動(dòng)拋出
NullPointerException 異常。這省去了重復(fù)編寫(xiě)if語(yǔ)句和拋出空指針異常的麻煩。
練習(xí)andThen:格式化打印信息
下面的字符串?dāng)?shù)組當(dāng)中存有多條信息,請(qǐng)按照格式“ 姓名:XX。性別:XX?!钡母袷綄⑿畔⒋蛴〕鰜?lái)。要求將打印姓名的動(dòng)作作為第一個(gè)Consumer 接口的Lambda實(shí)例,將打印性別的動(dòng)作作為第二個(gè)Consumer 接口的Lambda實(shí)例,將兩個(gè)Consumer 接口按照順序“拼接”到一起。
3.3 Predicate接口
作用:對(duì)數(shù)據(jù)類(lèi)型的數(shù)據(jù)進(jìn)行判斷,結(jié)果返回boolean值
抽象方法test:用來(lái)對(duì)指定數(shù)據(jù)類(lèi)型的數(shù)據(jù)進(jìn)行判斷的方法
public static boolean checkString(String s, Predicate<String> pre){return pre.test(s);}public static void main(String[] args) {String s = "abcd";boolean check = checkString(s, (str) -> str.length() > 5);System.out.println(check);}默認(rèn)方法and:
既然是條件判斷,就會(huì)存在與、或、非三種常見(jiàn)的邏輯關(guān)系。其中將兩個(gè)Predicate 條件使用“與”邏輯連接起來(lái)實(shí)現(xiàn)“并且”的效果時(shí),可以使用default方法and 。其JDK源碼為:
定義兩個(gè)判斷條件:字符串長(zhǎng)度大于5,字符串包含a,條件要同時(shí)滿足
public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){return pre1.and(pre2).test(s);//相當(dāng)于👇//return pre1.test(s) && pre2.test(s);}public static void main(String[] args) {String s = "abcdef";boolean check = checkString(s, (str) -> str.length() > 5,(str) -> str.contains("a"));System.out.println(check);}默認(rèn)方法or
與and 的“與”類(lèi)似,默認(rèn)方法or 實(shí)現(xiàn)邏輯關(guān)系中的“或”。JDK源碼為:
定義兩個(gè)判斷條件:字符串長(zhǎng)度大于5,字符串包含a,條件滿足一個(gè)即可
public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){return pre1.or(pre2).test(s);//相當(dāng)于👇 // return pre1.test(s) || pre2.test(s);}public static void main(String[] args) {String s = "a";boolean check = checkString(s, (str) -> str.length() > 5,(str) -> str.contains("a"));System.out.println(check);}默認(rèn)方法negate:“非”(取反)默認(rèn)方法negate 的JDK源代碼為:
default Predicate<T> negate() {return (t) ‐> !test(t); } public static boolean checkString(String s, Predicate<String> pre){return pre.negate().test(s);//相當(dāng)于👇//return !pre.test(s);}public static void main(String[] args) {String s = "a";boolean check = checkString(s, (str) -> str.length() > 5);System.out.println(check);}練習(xí):信息集合篩選
數(shù)組當(dāng)中有多條“姓名+性別”的信息如下,請(qǐng)通過(guò)Predicate 接口的拼裝將符合要求的字符串篩選到集合ArrayList 中,需要同時(shí)滿足兩個(gè)條件:
3.4 Function接口
java.util.function.Function<T,R> 接口用來(lái)根據(jù)一個(gè)類(lèi)型的數(shù)據(jù)得到另一個(gè)類(lèi)型的數(shù)據(jù),前者稱(chēng)為前置條件,后者稱(chēng)為后置條件。
使用場(chǎng)景:根據(jù)類(lèi)型T的參數(shù)獲取類(lèi)型R的結(jié)果
抽象方法:apply
public static void change(String s, Function<String, Integer> fun){Integer in = fun.apply(s);System.out.println(in);}public static void main(String[] args) {String s = "1234";change(s, (str)->{return Integer.parseInt(s);});}默認(rèn)方法:andThen
把String類(lèi)型的123轉(zhuǎn)換為Integer類(lèi)型,加上10后,再轉(zhuǎn)為String類(lèi)型輸出
練習(xí):自定義函數(shù)模型的拼接
請(qǐng)使用Function 進(jìn)行函數(shù)模型的拼接,按照順序需要執(zhí)行的多個(gè)函數(shù)操作為:
總結(jié)
以上是生活随笔為你收集整理的【Java】函数式编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 推荐几个Android开发非常有用的工具
- 下一篇: 【Java】第一阶段练习题