Java中的函數(shù)式編程
函數(shù)式編程是一種編程范式,其中程序是通過(guò)應(yīng)用和組合函數(shù)來(lái)構(gòu)造的。它是一種聲明式編程范式,其中函數(shù)定義是表達(dá)式樹(shù),每個(gè)表達(dá)式樹(shù)返回一個(gè)值,而不是一系列改變程序狀態(tài)的命令語(yǔ)句
Java8
引入了Lambda
形式的函數(shù)式編程。術(shù)語(yǔ)Lambda
來(lái)自Lambda
演算,用于描述計(jì)算。
1、Lambda
我們可以將lambda
表達(dá)式視為一個(gè)匿名函數(shù),可以將其分配給變量并傳遞給方法,該方法接受函數(shù)接口作為參數(shù)。Lambda表達(dá)式?jīng)]有名稱,但它有一個(gè)參數(shù)列表、一個(gè)主體和一個(gè)返回類型。
(parameters) -> expression
lambda
表達(dá)式可以在函數(shù)接口的上下文中使用。
2、函數(shù)接口
函數(shù)接口是只指定一個(gè)抽象方法的接口。
public interface Comparator<T> { int compare(T o1, T o2); } public interface Runnable { void run(); }
Lambda
表達(dá)式允許我們直接內(nèi)聯(lián)提供函數(shù)接口的抽象方法的實(shí)現(xiàn),并將整個(gè)表達(dá)式視為函數(shù)接口的實(shí)例。
2.1 函數(shù)描述符
我們將函數(shù)接口的抽象方法的簽名稱為函數(shù)描述符。函數(shù)描述符描述lambda
表達(dá)式的簽名。例如,我們可以將 Runnable
的函數(shù)描述符看作 ()->void
,因?yàn)樗幸粋€(gè)抽象方法,不接受任何內(nèi)容,也不返回任何內(nèi)容(void
)。
3、Java函數(shù)接口
3.1 Predicate
Predicate<T>
接口定義了一個(gè)名為 test
的抽象方法,該方法接受一個(gè)泛型類型為 T
的對(duì)象并返回一個(gè)布爾值。此接口可用于表示使用T類型對(duì)象的布爾表達(dá)式。
函數(shù)描述符: T->boolean
@FunctionalInterface public interface Predicate<T> { boolean test(T t); }
3.2 Consumer
java.util.function.Consumer<T>
接口定義了一個(gè)名為 accept
的抽象方法,該方法接受一個(gè)泛型類型為 T 的對(duì)象,并且不返回任何結(jié)果( void )。當(dāng)我們需要訪問(wèn)T類型的對(duì)象并對(duì)其執(zhí)行某些操作時(shí),可以使用此接口。
函數(shù)描述符: T->void
3.3 Function
java.util.function.function<T,R>
接口定義了一個(gè)名為 apply
的抽象方法,該方法將一個(gè)泛型類型為 T 的對(duì)象作為輸入,并返回一個(gè)泛型類型為 R 的對(duì)象。當(dāng)我們需要定義一個(gè)lambda
將信息從輸入對(duì)象映射到輸出時(shí),可以使用該接口。
函數(shù)描述符: T->R
3.4 Supplier
接口 java.util.function.Supplier<T>
定義了一個(gè)名為 get
的抽象方法,該方法不接受任何內(nèi)容并返回類型為T(mén)的對(duì)象。
函數(shù)描述符: ()->R
3.5 Primitive Specializations
原語(yǔ)接口是專用接口,用于在輸入或輸出為原語(yǔ)時(shí)避免自動(dòng)裝箱操作。
public interface IntPredicate { boolean test(int t); }
4、類型檢查
lambda
的類型是從使用lambda
的上下文中推導(dǎo)出來(lái)的。上下文中lambda
表達(dá)式所需的類型(例如,傳遞給它的方法參數(shù)或分配給它的局部變量)稱為目標(biāo)類型。Lambda
表達(dá)式可以從賦值上下文、方法調(diào)用上下文(參數(shù)和返回)和強(qiáng)制轉(zhuǎn)換上下文中獲取其目標(biāo)類型。
Object o = (Runnable) () -> System.out.println("Hello");
4.1 Capturing Lambda
lambda
可以不受限制地捕獲(在其主體中引用)實(shí)例變量和靜態(tài)變量。但是當(dāng)捕獲局部變量時(shí),它們必須顯式地聲明為 final 或?qū)嶋H上是 final
。
我們?yōu)楹斡羞@個(gè)限制?
實(shí)例變量存儲(chǔ)在堆上,而局部變量位于堆棧上。如果lambda
可以直接訪問(wèn)局部變量,并且lambda
在線程中使用,那么使用lambda
的線程可以在分配變量的線程解除分配變量后嘗試訪問(wèn)該變量。因此,Java
將對(duì)自由局部變量的訪問(wèn)實(shí)現(xiàn)為對(duì)其副本的訪問(wèn),而不是對(duì)原始變量的訪問(wèn)。如果局部變量只分配給一次,則這沒(méi)有什么區(qū)別,因此存在限制。
5、方法引用
有三種主要的方法參考:
- 對(duì)靜態(tài)方法的方法引用。例如,
– Integer::parseInt
- 對(duì)任意類型的實(shí)例方法的方法引用。示例
– String::length
- 對(duì)現(xiàn)有對(duì)象或表達(dá)式的實(shí)例方法的方法引用。示例
– student::getRank
,其中student
是具有方法getRank()
的student
類型的局部變量
List<String> list = Arrays.asList("a","b","A","B"); list.sort((s1, s2) -> s1.compareToIgnoreCase(s2));
可以寫(xiě)成
List<String> list = Arrays.asList("a","b","A","B"); list.sort(String::compareToIgnoreCase);
5.1 構(gòu)造函數(shù)引用
可以使用 ClassName::new
引用現(xiàn)有構(gòu)造函數(shù)
Supplier<List<String>> supplier = ArrayList::new ;與 Supplier<List<String>> supplier = () -> new ArrayList<>() 相同;
5.2 組合Lambda
許多函數(shù)接口包含可用于組合lambda
表達(dá)式的默認(rèn)方法。組合示例-
將兩個(gè)謂詞組合成一個(gè)較大的謂詞,在兩個(gè)謂詞之間執(zhí)行or操作
反向或鏈?zhǔn)奖容^器
5.3 Comparators
按逆序排列學(xué)生
Comparator<Student> c = Comparator.comparing(Student::getRank); students.sort(comparing(Student::getRank).reversed());
根據(jù)姓名(反向)對(duì)學(xué)生進(jìn)行排序,然后按反向順序排列
students.sort(comparing(Student::getName).reversed() .thenComparing(Student::getRank));
5.4 Predicates
Predicates接口包括三個(gè)方法: negate
, and
, 和 or
,可用于創(chuàng)建更復(fù)雜的謂詞。
Predicate<Integer> naturalNumber = i -> i > 0; Predicate<Integer> naturalNumberLessThanHundred = naturalNumber.and( i -> i < 100);
5.5 Functions
函數(shù)接口帶有兩個(gè)默認(rèn)方法, andThen
和 compose
。
Consider f(x) = x2 and g(x) = x3 + 1 then
g(f(x)) ->
Function<Integer,Integer> square = n -> n*n; Function<Integer,Integer> squareAndCube = square.andThen(n -> n*n*n+1); System.out.println(squareAndCube.apply(2)); 65
f(g(x)) ->
Function<Integer,Integer> square = n -> n*n; Function<Integer,Integer> squareAndCube = square.compose(n -> n*n*n + 1); System.out.println(squareAndCube.apply(2));
應(yīng)用Lambda
讓我們看看如何編寫(xiě)一個(gè)通用方法來(lái)根據(jù) veratain
屬性過(guò)濾一組書(shū)籍(將其視為sql
的where
子句)。
public static List<Book> filter(Predicate<Book> where) { List<Book> books = Catalogue.books(); return books.stream().filter(where).collect(Collectors.toList()); }
Lambda
表達(dá)式通過(guò)不同的過(guò)濾器過(guò)濾不同的書(shū)籍
List<Book> javaBook = filter(book -> book.getCategory().equals(JAVA)); List<Book> joshuaBlochBook = filter(book -> book.getAuthor().equals("Joshua Bloch"));
6、總結(jié)
lambda
表達(dá)式可以被認(rèn)為是一個(gè)匿名函數(shù),可以在函數(shù)接口的上下文中使用。函數(shù)接口是只指定一個(gè)抽象方法的接口。
到此這篇關(guān)于Java中的函數(shù)式編程的文章就介紹到這了,更多相關(guān)Java 函數(shù)式編程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
@RequestBody時(shí)第二個(gè)字母大寫(xiě),映射不到的解決
這篇文章主要介紹了@RequestBody時(shí)第二個(gè)字母大寫(xiě),映射不到的解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07淺析java實(shí)現(xiàn)數(shù)據(jù)加密問(wèn)題
本文通過(guò)實(shí)例代碼給大家介紹了java實(shí)現(xiàn)數(shù)據(jù)加密問(wèn)題,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2019-11-11Spring Boot使用profile如何配置不同環(huán)境的配置文件
,springboot支持通過(guò)不同的profile來(lái)配置不同環(huán)境的配置,下面就大致介紹一下yml配置文件跟properties配置文件怎么使用profile配置不同環(huán)境的配置文件2018-01-01實(shí)戰(zhàn)分布式醫(yī)療掛號(hào)系統(tǒng)之設(shè)置微服務(wù)搭建醫(yī)院模塊
這篇文章主要為大家介紹了實(shí)戰(zhàn)分布式醫(yī)療掛號(hào)系統(tǒng)之搭建醫(yī)院設(shè)置微服務(wù)模塊,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04Springboot如何同時(shí)裝配兩個(gè)相同類型數(shù)據(jù)庫(kù)
這篇文章主要介紹了Springboot如何同時(shí)裝配兩個(gè)相同類型數(shù)據(jù)庫(kù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Java SpringMVC實(shí)現(xiàn)國(guó)際化整合案例分析(i18n)
本篇文章主要介紹了Java SpringMVC實(shí)現(xiàn)國(guó)際化整合案例分析(i18n),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05JavaWeb Servlet生命周期細(xì)枝末節(jié)處深究
Servlet指在服務(wù)器端執(zhí)行的一段Java代碼,可以接收用戶的請(qǐng)求和返回給用戶響應(yīng)結(jié)果,下面這篇文章主要給大家介紹了關(guān)于JavaWeb.servlet生命周期的相關(guān)資料,需要的朋友可以參考下2022-10-10