Java 函數(shù)式編程要點(diǎn)總結(jié)
一、函數(shù)式概念
函數(shù)式編程是一種結(jié)構(gòu)化編程的范式,主要思想是把運(yùn)算過(guò)程盡量寫成系列嵌套的函數(shù)調(diào)用。函數(shù)編程的概念表述帶有很抽象的感覺,可以基于案例看:
public class Function01 { public static void main(String[] args) { // 運(yùn)算:(x+y)* c int x1 = 2 ; int y1 = 3 ; int c1 = 4 ; int sum1 = x1 + y1 ; int res1 = sum1 * c1 ; System.out.println("res1 = "+res1); } }
這里基于過(guò)程的方式做計(jì)算,上面的代碼塊著重在描述程序執(zhí)行過(guò)程。
在看基于函數(shù)的方式解決方法:
public class Function02 { public static void main(String[] args) { // 函數(shù)式計(jì)算 System.out.println("func01 = "+func01(2,3,4)); } private static int func01 (int x,int y,int c){ return (x+y)*c; } }
函數(shù)式編程的核心要素:傳入?yún)?shù),執(zhí)行邏輯,返回值,也可以沒有返回值。
函數(shù)式的編程風(fēng)格側(cè)重描述程序的執(zhí)行邏輯,不是執(zhí)行過(guò)程。
同上面計(jì)算過(guò)程相比,函數(shù)式編程也減少很多臨時(shí)變量的創(chuàng)建,代碼風(fēng)格也變的簡(jiǎn)潔清楚。
二、函數(shù)與方法
在Java語(yǔ)言中有函數(shù)式編程風(fēng)格,但是Java代碼中沒有函數(shù)的說(shuō)法,而是稱為:方法;
public class Function03 { public static void main(String[] args) { Func03 func03 = new Func03(); func03.add(2); System.out.println(func03.res1); } } class Func03 { public int res1 = 0 ; public void add (int a1){ this.res1 = a1 +1 ; } }
類定義引用數(shù)據(jù)類型,類實(shí)例化后的對(duì)象可以調(diào)用類內(nèi)部的方法和數(shù)據(jù),這是最直觀的感覺。
但是方法又有靜態(tài)和非靜態(tài)的區(qū)別,靜態(tài)方法屬于類所有,類實(shí)例化前即可使用。
非靜態(tài)方法可以訪問(wèn)類中的任何成員變量和方法,并且必須是類實(shí)例化后的對(duì)象才可以調(diào)用。
三、JDK函數(shù)基礎(chǔ)
1、Lambda表達(dá)式
Lambda表達(dá)式也可稱為閉包,是推動(dòng)Java8發(fā)布的最重要新特性,允許把函數(shù)作為一個(gè)方法的參數(shù)(函數(shù)作為參數(shù)傳遞進(jìn)方法中)。
這里就很鮮明的對(duì)比Lambda表達(dá)式語(yǔ)法和傳統(tǒng)用法。
public class Lambda01 { interface LambdaOpera { int operation(int a, int b); } public static void main(String[] args) { LambdaOpera lambdaOpera = new LambdaOpera(){ @Override public int operation(int a, int b) { return a * b ; } }; System.out.println(lambdaOpera.operation(3,2)); LambdaOpera lambdaOpera01 = (int a, int b) -> a + b; LambdaOpera lambdaOpera02 = (int a, int b) -> a - b; System.out.println(lambdaOpera01.operation(3,2)); System.out.println(lambdaOpera02.operation(3,2)); } }
在看一個(gè)直觀的應(yīng)用案例,基于Lambda的方式創(chuàng)建線程,可以使代碼變的更加簡(jiǎn)潔緊湊:
public class Lambda02 { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 2; i++) { System.out.println(i); } } }).start(); // 對(duì)比 Lambda 方式 new Thread(() -> { for (int i = 0; i < 2; i++) { System.out.println(i); } }).start(); } }
在看一下Runnable接口的結(jié)構(gòu):
FunctionalInterface標(biāo)記在接口上,表示該接口是函數(shù)式接口,并且該接口只包含一個(gè)抽象方法,
@FunctionalInterface public interface Runnable { public abstract void run(); }
Lambda表達(dá)式本身可以理解為就是一個(gè)接口的實(shí)現(xiàn)過(guò)程,這里runnable就是完整的Lambda表達(dá)式聲明:
public class Lambda04 { public static void main(String[] args) { Runnable runnable = () -> { System.out.println("run one..."); }; Thread thread = new Thread(runnable); thread.start(); } }
Lambda表達(dá)式最直觀的作用就是使得代碼變得異常簡(jiǎn)潔,并且可以作為參數(shù)傳遞。
2、函數(shù)式接口
Lambda表達(dá)式雖然有很多優(yōu)點(diǎn),但是使用的時(shí)候需要定義一些接口用來(lái)完成編碼,這樣又使得表達(dá)式又變得重量級(jí),Java8自身已經(jīng)提供幾個(gè)常見的函數(shù)式接口。
- Function:輸入一個(gè)參數(shù),返回一個(gè)結(jié)果;
- Consumer:輸入一個(gè)參數(shù),不返回結(jié)果;
- BiFunction:輸入兩個(gè)參數(shù),返回一個(gè)結(jié)果;
- BiConsumer:輸入兩個(gè)參數(shù),不返回任何結(jié)果;
public class Lambda05 { public static void main(String[] args) { Function<Integer, Integer> function01 = x -> x * 2; System.out.println(function01.apply(2)); BiFunction<Integer, Integer, Integer> function02 = (x, y) -> x * y; System.out.println(function02.apply(2, 3)); Consumer<String> consumer01 = msg -> System.out.println("msg:"+msg); consumer01.accept("hello"); BiConsumer<String,Integer> consumer02 = (msg,i) -> System.out.println(msg+":"+i); consumer02.accept("world",3); } }
如果面對(duì)更復(fù)雜的業(yè)務(wù)需求,可以自定義函數(shù)式接口去解決。
四、Optional類
1、Null判斷
Optional類是Java函數(shù)式編程的應(yīng)用,主要用來(lái)解決常見的空指針異常問(wèn)題。
在Java編程的開發(fā)中,很多地方都能常見空指針異常的拋出,如果想避免這個(gè)問(wèn)題就要加入很多判斷:
public class Optional01 { public static void main(String[] args) { User user = new User(1,"hello") ; if (user != null){ if (user.getName() != null){ System.out.println(user.getName()); } } } }
為了確保程序不拋出空指針這種低級(jí)的錯(cuò)誤,在程序中隨處可以null的判斷,代碼顯然冗余和繁雜。
2、Optional應(yīng)用
基于Optional類創(chuàng)建的對(duì)象可能包含空值和null值,也同樣會(huì)拋出對(duì)應(yīng)的異常:
public class Optional02 { public static void main(String[] args) { // NoSuchElementException Optional<User> optionalUser = Optional.empty(); optionalUser.get(); // NullPointerException Optional<User> nullOpt = Optional.of(null); nullOpt.get(); } }
所以在不明確對(duì)象的具體情況下,使用ofNullable()方法:
public class Optional03 { public static void main(String[] args) { User user = new User(1,"say"); Optional<User> optionalUser = Optional.ofNullable(user); if (optionalUser.isPresent()){ System.out.println(optionalUser.get().getName()); } User user1 = null ; User createUser = Optional.ofNullable(user1).orElse(createUser()); System.out.println(createUser.getName()); User user2 = null ; Optional.ofNullable(user2).orElseThrow( () -> new RuntimeException());; } public static User createUser (){ return new User(2,"hello") ; } }
這樣看下來(lái)Optional結(jié)合鏈?zhǔn)椒椒ê蚅ambda表達(dá)式就很大程度上簡(jiǎn)化了應(yīng)用的代碼量:
public class Optional04 { public static void main(String[] args) { // 1、map轉(zhuǎn)換方法 User user = new User(99, "Java"); // user = null ; String name = Optional.ofNullable(user) .map(u -> u.getName()).orElse("c++"); System.out.println(name); // 2、過(guò)濾方法 Optional<User> optUser01 = Optional.ofNullable(user) .filter(u -> u.getName() != null && u.getName().contains("c++")); // NoSuchElementException System.out.println(optUser01.get().getName()); } }
Optional提供null處理的各種方法,可以簡(jiǎn)潔很多代碼判斷,但是在使用風(fēng)格上和之前變化很大。
五、Stream流
如果Optional簡(jiǎn)化很多Null的判斷,那Stream流的API則簡(jiǎn)化了很多集合的遍歷判斷,同樣也是基于函數(shù)式編程。
上述為Stream接口繼承關(guān)系如圖,同樣提供一些特定接口和較大的包裝接口,通過(guò)源碼查看,可以看到和函數(shù)編程也是密切相關(guān)。
public class Stream01 { public static void main(String[] args) { Stream<String> stream = Stream.of("hello", "java"); stream.forEach(str -> System.out.print(str+";")); } }
Stream與函數(shù)接口結(jié)合使用,函數(shù)接口又可以使用Lambda表達(dá)式進(jìn)行簡(jiǎn)化代碼。在Java8通過(guò)Stream可以大量簡(jiǎn)化集合使用的代碼復(fù)雜度。
public class Stream02 { public static void main(String[] args) { // 1、轉(zhuǎn)換Stream List<String> list = Arrays.asList("java+;", "c++;", "net;"); list.stream(); // 2、forEach操作 list.stream().forEach(System.out::print); // 3、map映射,輸出 3,4 IntStream.rangeClosed(2,3).map(x->x+1).forEach(System.out::println); // 4、filter過(guò)濾 list.stream().filter(str -> str.contains("+")).forEach(System.out::print); // 5、distinct去重 Integer[] arr = new Integer[]{3, 1, 3, 1, 2,4}; Stream.of(arr).distinct().forEach(System.out::println); // 6、sorted排序 Stream.of(arr).sorted().forEach(System.out::println); // 7、collect轉(zhuǎn)換 List<String> newList = list.stream().filter(str -> str.contains("+")) .collect(Collectors.toList()); newList.stream().forEach(System.out::print); } }
在沒有Stream相關(guān)API之前,對(duì)于集合的操作和遍歷都會(huì)產(chǎn)生大量的代碼,通過(guò)Stream相關(guān)API集合的函數(shù)式編程和Lambda表達(dá)式的風(fēng)格,簡(jiǎn)化集合很多操作。
六、源代碼地址
GitHub·地址
https://github.com/cicadasmile/java-base-parent
GitEE·地址
https://gitee.com/cicadasmile/java-base-parent
以上就是Java 函數(shù)式編程要點(diǎn)總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于Java 函數(shù)式編程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用Java實(shí)現(xiàn)將ppt轉(zhuǎn)換為文本
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)將ppt轉(zhuǎn)換為文本,文中的示例代碼簡(jiǎn)潔易懂,具有一定的借鑒價(jià)值,有需要的小伙伴可以參考下2024-01-01SpringBoot 如何添加容器啟動(dòng)的初始化邏輯的操作方法
這篇文章主要介紹了SpringBoot 如何添加容器啟動(dòng)的初始化邏輯,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09Java設(shè)計(jì)模式編程中的工廠方法模式和抽象工廠模式
這篇文章主要介紹了Java設(shè)計(jì)模式編程中的工廠方法模式和抽象工廠模式,設(shè)計(jì)模式的建立有利于團(tuán)隊(duì)協(xié)作時(shí)代碼的共同維護(hù),需要的朋友可以參考下2016-01-01spring Boot打包部署到遠(yuǎn)程服務(wù)器的tomcat中
這篇文章主要給大家介紹了關(guān)于spring Boot打包部署到遠(yuǎn)程服務(wù)器的tomcat中的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12selenium高效應(yīng)對(duì)Web頁(yè)面元素刷新的實(shí)例講解
今天小編就為大家分享一篇selenium高效應(yīng)對(duì)Web頁(yè)面元素刷新的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05java版微信公眾平臺(tái)消息接口應(yīng)用示例
這篇文章主要介紹了java版微信公眾平臺(tái)消息接口應(yīng)用,結(jié)合實(shí)例形式對(duì)比分析了PHP與java應(yīng)用微信公眾平臺(tái)接口的相關(guān)調(diào)用與操作技巧,需要的朋友可以參考下2017-07-07Java實(shí)現(xiàn)學(xué)生信息管理界面
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)學(xué)生信息管理界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06Hystrix?Turbine聚合監(jiān)控的實(shí)現(xiàn)詳解
微服務(wù)架構(gòu)下,?個(gè)微服務(wù)往往部署多個(gè)實(shí)例,如果每次只能查看單個(gè)實(shí)例的監(jiān)控,就需要經(jīng)常切換很不?便,在這樣的場(chǎng)景下,我們可以使??Hystrix?Turbine?進(jìn)?聚合監(jiān)控,它可以把相關(guān)微服務(wù)的監(jiān)控?cái)?shù)據(jù)聚合在?起,便于查看2022-09-09解決springcloud中Feign導(dǎo)入依賴為unknow的情況
這篇文章主要介紹了解決springcloud中Feign導(dǎo)入依賴為unknow的情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03