函數式編程是一種編程范式,其中程序是通過應用和組合函數來構造的。它是一種聲明式編程范式,其中函數定義是表達式樹,每個表達式樹返回一個值,而不是一系列改變程序狀態的命令語句
Java8
引入了Lambda
形式的函數式編程。術語Lambda
來自Lambda
演算,用于描述計算。
1、Lambda
我們可以將lambda
表達式視為一個匿名函數,可以將其分配給變量并傳遞給方法,該方法接受函數接口作為參數。Lambda表達式沒有名稱,但它有一個參數列表、一個主體和一個返回類型。
(parameters) -> expression
lambda
表達式可以在函數接口的上下文中使用。
2、函數接口
函數接口是只指定一個抽象方法的接口。
1
2
3
4
5
6
|
public interface Comparator<T> { int compare(T o1, T o2); } public interface Runnable { void run(); } |
Lambda
表達式允許我們直接內聯提供函數接口的抽象方法的實現,并將整個表達式視為函數接口的實例。
2.1 函數描述符
我們將函數接口的抽象方法的簽名稱為函數描述符。函數描述符描述lambda
表達式的簽名。例如,我們可以將 Runnable
的函數描述符看作 ()->void
,因為它有一個抽象方法,不接受任何內容,也不返回任何內容(void
)。
3、Java函數接口
3.1 Predicate
Predicate<T>
接口定義了一個名為 test
的抽象方法,該方法接受一個泛型類型為 T
的對象并返回一個布爾值。此接口可用于表示使用T類型對象的布爾表達式。
函數描述符: T->boolean
1
2
3
4
|
@FunctionalInterface public interface Predicate<T> { boolean test(T t); } |
3.2 Consumer
java.util.function.Consumer<T>
接口定義了一個名為 accept
的抽象方法,該方法接受一個泛型類型為 T 的對象,并且不返回任何結果( void )。當我們需要訪問T類型的對象并對其執行某些操作時,可以使用此接口。
函數描述符: T->void
3.3 Function
java.util.function.function<T,R>
接口定義了一個名為 apply
的抽象方法,該方法將一個泛型類型為 T 的對象作為輸入,并返回一個泛型類型為 R 的對象。當我們需要定義一個lambda
將信息從輸入對象映射到輸出時,可以使用該接口。
函數描述符: T->R
3.4 Supplier
接口 java.util.function.Supplier<T>
定義了一個名為 get
的抽象方法,該方法不接受任何內容并返回類型為T的對象。
函數描述符: ()->R
3.5 Primitive Specializations
原語接口是專用接口,用于在輸入或輸出為原語時避免自動裝箱操作。
1
2
3
|
public interface IntPredicate { boolean test( int t); } |
4、類型檢查
lambda
的類型是從使用lambda
的上下文中推導出來的。上下文中lambda
表達式所需的類型(例如,傳遞給它的方法參數或分配給它的局部變量)稱為目標類型。Lambda
表達式可以從賦值上下文、方法調用上下文(參數和返回)和強制轉換上下文中獲取其目標類型。
1
|
Object o = (Runnable) () -> System.out.println( "Hello" ); |
4.1 Capturing Lambda
lambda
可以不受限制地捕獲(在其主體中引用)實例變量和靜態變量。但是當捕獲局部變量時,它們必須顯式地聲明為 final 或實際上是 final
。
我們為何有這個限制?
實例變量存儲在堆上,而局部變量位于堆棧上。如果lambda
可以直接訪問局部變量,并且lambda
在線程中使用,那么使用lambda
的線程可以在分配變量的線程解除分配變量后嘗試訪問該變量。因此,Java
將對自由局部變量的訪問實現為對其副本的訪問,而不是對原始變量的訪問。如果局部變量只分配給一次,則這沒有什么區別,因此存在限制。
5、方法引用
有三種主要的方法參考:
-
對靜態方法的方法引用。例如,
– Integer::parseInt
-
對任意類型的實例方法的方法引用。示例
– String::length
-
對現有對象或表達式的實例方法的方法引用。示例
– student::getRank
,其中student
是具有方法getRank()
的student
類型的局部變量
1
2
|
List<String> list = Arrays.asList( "a" , "b" , "A" , "B" ); list.sort((s1, s2) -> s1.compareToIgnoreCase(s2)); |
可以寫成
1
2
|
List<String> list = Arrays.asList( "a" , "b" , "A" , "B" ); list.sort(String::compareToIgnoreCase); |
5.1 構造函數引用
可以使用 ClassName::new
引用現有構造函數
1
|
Supplier<List<String>> supplier = ArrayList:: new ;與 Supplier<List<String>> supplier = () -> new ArrayList<>() 相同; |
5.2 組合Lambda
許多函數接口包含可用于組合lambda
表達式的默認方法。組合示例-
將兩個謂詞組合成一個較大的謂詞,在兩個謂詞之間執行or操作
反向或鏈式比較器
5.3 Comparators
按逆序排列學生
1
2
|
Comparator<Student> c = Comparator.comparing(Student::getRank); students.sort(comparing(Student::getRank).reversed()); |
根據姓名(反向)對學生進行排序,然后按反向順序排列
1
2
|
students.sort(comparing(Student::getName).reversed() .thenComparing(Student::getRank)); |
5.4 Predicates
Predicates接口包括三個方法: negate
, and
, 和 or
,可用于創建更復雜的謂詞。
1
2
|
Predicate<Integer> naturalNumber = i -> i > 0 ; Predicate<Integer> naturalNumberLessThanHundred = naturalNumber.and( i -> i < 100 ); |
5.5 Functions
函數接口帶有兩個默認方法, andThen
和 compose
。
Consider f(x) = x2 and g(x) = x3 + 1 then
g(f(x)) ->
1
2
3
4
|
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)) ->
1
2
3
|
Function<Integer,Integer> square = n -> n*n; Function<Integer,Integer> squareAndCube = square.compose(n -> n*n*n + 1 ); System.out.println(squareAndCube.apply( 2 )); |
應用Lambda
讓我們看看如何編寫一個通用方法來根據 veratain
屬性過濾一組書籍(將其視為sql
的where
子句)。
1
2
3
4
|
public static List<Book> filter(Predicate<Book> where) { List<Book> books = Catalogue.books(); return books.stream().filter(where).collect(Collectors.toList()); } |
Lambda
表達式通過不同的過濾器過濾不同的書籍
1
2
|
List<Book> javaBook = filter(book -> book.getCategory().equals(JAVA)); List<Book> joshuaBlochBook = filter(book -> book.getAuthor().equals( "Joshua Bloch" )); |
6、總結
lambda
表達式可以被認為是一個匿名函數,可以在函數接口的上下文中使用。函數接口是只指定一個抽象方法的接口。
到此這篇關于Java中的函數式編程的文章就介紹到這了,更多相關Java 函數式編程內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://javakk.com/2449.html?utm_source=tuicool&utm_medium=referral