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