Java8学习系列之匿名函数Lambda
Lambda介紹
Lambda,別名函數式編程,維基百科給出以下介紹:
函數式編程是一種編程范式。它把計算當成是數學函數的求值,從而避免改變狀態和使用可變數據。它是一種聲明式的編程范式,通過表達式和聲明而不是語句來編程。
Lambda表達式基于數學中的λ演算得名,直接對應于其中的lambda抽象(lambda abstraction),是一個匿名函數,即沒有函數名的函數。Lambda表達式可以表示閉包(注意和數學傳統意義上的不同)。
λ 演算是數理邏輯中的一個形式系統,在函數抽象和應用的基礎上,使用變量綁定和替換來表達計算。討論 λ 演算離不開形式化的表達。在本文中,我們盡量集中在與編程相關的基本概念上,而不拘泥于數學上的形式化表示。λ 演算實際上是對前面提到的函數概念的簡化,方便以系統的方式來研究函數。
Java中的Lambda
自Java8面世以后,也就代表著java從此以后同樣支持lambda語法,使得之前繁瑣的操作都可以使用簡便的語法進行代替,最具代表性的改革就是新增的Stream類,讓我們對一個集合的排序、過濾、映射和采集更加方便!
我們擬定一個場景,對于給定的一個int數組,過濾掉負數,并對剩余的元素進行排序,在java8之前我們的實現需要這么寫:
int[] array = {7, -2, 3, 5, -9, 3, -5, -1, 6, 8, 20}; List<Integer> list = new ArrayList<Integer>(); //過濾負數 for(int i: array) {if(i >= 0) list.add(i); } //排序 Collections.sort(list);for(int i: list) {System.out.println(i); } 復制代碼使用Stream之后:
int[] array = {7, -2, 3, 5, -9, 3, -5, -1, 6, 8, 20}; Arrays.stream(array).filter(a -> a >= 0) //過濾.sorted() //排序.forEach(System.out::println); 復制代碼可以看到,實現的過程更加簡潔和優雅,lambda大大節省了代碼空間,提升了代碼可讀性,但使用的難度也隨之提高,對于傳統的編程方式,lambda語法無疑是一次重大的沖擊。
Java中Lambda語法的使用
函數式接口
什么是函數式接口呢?在Java8之前,我們想實現一個接口,最簡單的方式直接使用匿名類:
Comparator<Integer> comparator = new Comparator<Integer>() {public int compare(Integer o1, Integer o2) {return o1 > o2 ? 1 : -1;} }; 復制代碼這里要注意,Comparator是一個接口類型,它的內部只有一個需要被實現的方法,那么我們將之稱之為函數式接口,一般的函數式接口都會加上@FunctionalInterface注解,如果該接口待實現的方法超出兩個,你的IDE就會提醒你這不是一個規范的函數式接口,對于符合的,我們就可以使用lambda語法進行初始化:
Comparator<Integer> comparator = (o1, o2) -> o1 > o2 ? 1 : -1; 復制代碼將之與java8之前的實現對比,我們發現有很多共同之處,我們來分析一下lambda的實現:
(o1, o2) -> o1 > o2 ? 1 : -1; 復制代碼將上部分以->做分割線,分成兩部分,它們分別是(o1, o2)和o1 > o2 ? 1 : -1。很明顯,前者代表著函數的兩個入參,后者代表著兩個入參的邏輯實現,由此可得,lambda由兩部分組成:入參定義和邏輯實現。
對于一個函數式接口,我們可以用簡單的lambda語法去實現接口內唯一的待實現方法,反推一下,對于lambda這種匿名的函數定義風格,如果一個接口存在兩個待實現的方法,lambda則無法具體表示實現的是哪一個方法,由此反推可得,一個函數式接口最多只能有一個待實現方法。
JDK對Lambda的支持
通過函數式接口的定義和lambda實現我們知道了lambda語法的一個簡單格式,但是在開發過程中,我們不可能對于每一個lambda的應用都定義個函數式接口,實際上,JDK中已經存在了很多lambda函數:
- Function<T, R>:接受一個參數輸入,輸入類型為 T,輸出類型為 R。 抽象方法為R apply(T)。
- BiFunction<T, U, R>:接受兩個參數輸入, T 和 U 分別是兩個參數的類型,R 是輸出類型。抽象方法為R apply(T, U)。
- Consumer:接受一個輸入,沒有輸出。抽象方法為 void accept(T t)。
- Predicate:接受一個輸入,輸出為 boolean 類型。抽象方法為 boolean test(T t)。
- Supplier:沒有輸入,一個輸出。抽象方法為 T get()。
- BinaryOperator:接受兩個類型相同的輸入,輸出的類型與輸入相同,相當于 BiFunction<T,T,T>。
- UnaryOperator:接受一個輸入,輸出的類型與輸入相同,相當于 Function<T, T>。
- BiPredicate<T, U>:接受兩個輸入,輸出為 boolean 類型。抽象方法為 boolean test(T t, U u)。
它們分別應用于不同的場景,以下將會有幾個演示,首先使用lambda實現一個計算器:
BinaryOperator<Integer> cal = (a, b) -> a + b; System.out.println(bo.apply(1, 2)); // 3 復制代碼再來一個,使用lambda實現對數字正負的判斷
int a = 1; int b = -1; Predicate<Integer> predicate = i -> i >= 0; System.out.println(predicate.test(a)); //true System.out.println(predicate.test(b)); //false 復制代碼總結
在Stream中,lambda的應用非常廣泛,我們如果想講lambda更熟練的掌握,需要自己親自的去使用lambda,在實戰中去真正體會lambda的強大之處。
參考文章
- 深入理解Java函數式編程
- Java 8 中的 Streams API 詳解
- 百度百科——Lambda表達式
轉載于:https://juejin.im/post/5c49a485e51d4539b9281012
總結
以上是生活随笔為你收集整理的Java8学习系列之匿名函数Lambda的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 正则表达式下——相关方法
- 下一篇: 数据结构 引言