java8 Lambda表達(dá)式用法全集

什么是函數(shù)式編程

函數(shù)式編程(英語:functional programming)又稱函數(shù)程序設(shè)計(jì)和泛函編程,是一種編程范型,它將電腦運(yùn)算視為數(shù)學(xué)上的函數(shù)計(jì)算,并且避免使用程序狀態(tài)以及易變對(duì)象。函數(shù)編程語言最重要的基礎(chǔ)是λ演算(lambda calculus)。而且λ演算的函數(shù)可以接受函數(shù)當(dāng)作輸入(引數(shù))和輸出(傳出值)。

函數(shù)式風(fēng)格優(yōu)點(diǎn)

1、代碼簡潔

通常情況下,函數(shù)式編程更加簡明扼要,精簡的代碼更易于維護(hù)。而Java代碼的冗余性也是出了名的,大部分對(duì)于Java語言的攻擊都會(huì)直接針對(duì)Java繁瑣,而且死板的語法(不過這也不是缺點(diǎn)),然而,引入函數(shù)式編程范式后,這種情況發(fā)生了改變。我們可以讓Java用更少的代碼完成更多的工作。

代碼塊

Java

? ? static int[] arr = {1,3,4,5,6,7,8,9,10};? ? ?

? ? //傳統(tǒng)的處理方式:? ? ? ?

? ? for(int i=0;i<arr.length;i++){? ? ? ? ? ? ?

? ? ? if(arr[i]%2 != 0){? ? ? ? ? ? ? ? ?

? ? ? ? arr[i]++;? ? ? ? ? ? ?

? ? ? }? ? ? ? ? ? ?

? ? ? System.out.println(arr[i]);? ? ?

? ? }?

? ? //函數(shù)式處理方式:?

? ? arr.stream().map(x->(x%2==0?x:x+1)).foreach(System.out::println);

2、易于多線程

由于對(duì)象都處于不變的狀態(tài),因此函數(shù)式編程更加易于并行。實(shí)際上,你甚至完全不用擔(dān)心線程安全的問題。我們之所以要關(guān)注線程安全,一個(gè)很大的原因是當(dāng)多個(gè)線程對(duì)同一個(gè)對(duì)象進(jìn)行寫操作時(shí),容易“使得對(duì)象狀態(tài)不一致”。但是,由于不變模式的存在,對(duì)象自創(chuàng)建以來,就不可能發(fā)生改變,因此,在多線程環(huán)境下,也就沒有必要進(jìn)行任何同步操作。這樣不僅有利于并行化,同時(shí),在并行化后,由于沒有同步和鎖機(jī)制,其性能也會(huì)比較好。例如java.lang.String對(duì)象。很顯然,String對(duì)象可以在多線程中很好的工作,但是,得益于不變模式,它的每一個(gè)方法都沒有進(jìn)行同步處理。

3、可讀性更高

函數(shù)式編程風(fēng)格只需要聲明計(jì)算機(jī)需要干什么事,而不是像命令式風(fēng)格一樣將計(jì)算機(jī)的操作具體到每一步,所以可讀性會(huì)更高。

常用Lambda表達(dá)式

1.替代匿名內(nèi)部類

毫無疑問,lambda表達(dá)式用得最多的場合就是替代匿名內(nèi)部類,而實(shí)現(xiàn)Runnable接口是匿名內(nèi)部類的經(jīng)典例子。lambda表達(dá)式的功能相當(dāng)強(qiáng)大,用()->就可以代替整個(gè)匿名內(nèi)部類!請(qǐng)看代碼:

如果使用匿名內(nèi)部類:

代碼塊

Java

@Test

? ? public void oldRunable() {

? ? ? ? new Thread(new Runnable() {

? ? ? ? ? ? @Override

? ? ? ? ? ? public void run() {

? ? ? ? ? ? ? ? System.out.println("The old runable now is using!");

? ? ? ? ? ? }

? ? ? ? }).start();

? ? }

而如果使用lambda表達(dá)式:

代碼塊

Java

@Test

? ? public void runable() {

? ? ? ? new Thread(() -> System.out.println("It's a lambda function!")).start();

? ? }

2.使用lambda表達(dá)式對(duì)集合進(jìn)行迭代

Java的集合類是日常開發(fā)中經(jīng)常用到的,甚至說沒有哪個(gè)java代碼中沒有使用到集合類。。。而對(duì)集合類最常見的操作就是進(jìn)行迭代遍歷了。請(qǐng)看對(duì)比:

代碼塊

Java

@Test

? ? public void iterTest() {

? ? ? ? List<String> languages = Arrays.asList("java","scala","python");

? ? ? ? //before java8

? ? ? ? for(String each:languages) {

? ? ? ? ? ? System.out.println(each);

? ? ? ? }

? ? ? ? //after java8

? ? ? ? languages.forEach(x -> System.out.println(x));

? ? ? ? languages.forEach(System.out::println);

? ? }

3.用lambda表達(dá)式實(shí)現(xiàn)map

一提到函數(shù)式編程,一提到lambda表達(dá)式,怎么能不提map。。。沒錯(cuò),java8肯定也是支持的。請(qǐng)看示例代碼:

代碼塊

Java

@Test

? ? public void mapTest() {

? ? ? ? List<Double> cost = Arrays.asList(10.0, 20.0,30.0);

? ? ? ? cost.stream().map(x -> x + x*0.05).forEach(x -> System.out.println(x));

? ? }

map函數(shù)可以說是函數(shù)式編程里最重要的一個(gè)方法了。map的作用是將一個(gè)對(duì)象變換為另外一個(gè)。在我們的例子中,就是通過map方法將cost增加了0,05倍的大小然后輸出。

4.用lambda表達(dá)式實(shí)現(xiàn)map與reduce

既然提到了map,又怎能不提到reduce。reduce與map一樣,也是函數(shù)式編程里最重要的幾個(gè)方法之一。。map的作用是將一個(gè)對(duì)象變?yōu)榱硗庖粋€(gè),而reduce實(shí)現(xiàn)的則是將所有值合并為一個(gè),reduce方法允許我們用自己的方式去計(jì)算元素或者將一個(gè)Stream中的元素以某種規(guī)律關(guān)聯(lián)

代碼塊

Java

@Test

? ? public void mapReduceTest() {

? ? ? ? List<Double> cost = Arrays.asList(10.0, 20.0,30.0);

? ? ? ? double allCost = cost.stream().map(x -> x+x*0.05).reduce((sum,x) -> sum + x).get();

? ? ? ? System.out.println(allCost);

? ? }

最終的結(jié)果為:63.00

5.filter操作

filter也是我們經(jīng)常使用的一個(gè)操作。在操作集合的時(shí)候,經(jīng)常需要從原始的集合中過濾掉一部分元素。

代碼塊

Java

@Test

? ? public void filterTest() {

? ? ? ? List<Double> cost = Arrays.asList(10.0, 20.0,30.0,40.0);

? ? ? ? List<Double> filteredCost = cost.stream().filter(x -> x > 25.0).collect(Collectors.toList());

? ? ? ? filteredCost.forEach(x -> System.out.println(x));

? ? }

最終結(jié)果:30 40

6.與函數(shù)式接口Predicate配合

除了在語言層面支持函數(shù)式編程風(fēng)格,Java 8也添加了一個(gè)包,叫做 java.util.function。它包含了很多類,用來支持Java的函數(shù)式編程。其中一個(gè)便是Predicate,使用 java.util.function.Predicate 函數(shù)式接口以及l(fā)ambda表達(dá)式,可以向API方法添加邏輯,用更少的代碼支持更多的動(dòng)態(tài)行為。Predicate接口非常適用于做過濾。

代碼塊

Java

public static void filterTest(List<String> languages, Predicate<String> condition) {

? ? ? ? languages.stream().filter(x -> condition.test(x)).forEach(x -> System.out.println(x + " "));

? ? }

? ? public static void main(String[] args) {

? ? ? ? List<String> languages = Arrays.asList("Java","Python","scala","Shell","R");

? ? ? ? System.out.println("Language starts with J: ");

? ? ? ? filterTest(languages,x -> x.startsWith("J"));

? ? ? ? System.out.println("\nLanguage ends with a: ");

? ? ? ? filterTest(languages,x -> x.endsWith("a"));

? ? ? ? System.out.println("\nAll languages: ");

? ? ? ? filterTest(languages,x -> true);

? ? ? ? System.out.println("\nNo languages: ");

? ? ? ? filterTest(languages,x -> false);

? ? ? ? System.out.println("\nLanguage length bigger three: ");

? ? ? ? filterTest(languages,x -> x.length() > 4);

? ? }

可以看到,Stream API的過濾方法也接受一個(gè)Predicate,這意味著可以將我們定制的 filter() 方法替換成寫在里面的內(nèi)聯(lián)代碼。

7.Match(匹配)

用來判斷某個(gè)predicate是否和流對(duì)象相匹配,最終返回Boolean類型結(jié)果,例如

代碼塊

JSON

? ? List<String> list = new ArrayList<String>();

??? list.add("a1");

??? list.add("b1");

??? // 流對(duì)象中只要有一個(gè)元素匹配就返回true

??? boolean anyStartWithA = list.stream().anyMatch((s -> s.startsWith("a")));

??? System.out.println(anyStartWithA);

??? // 流對(duì)象中每個(gè)元素都匹配就返回true

??? boolean allStartWithA = list.stream().allMatch((s -> s.startsWith("a")));

??? System.out.println(allStartWithA);

8.Limit(限制)

imit 方法用于獲取指定數(shù)量的流。 以下代碼片段使用 limit 方法打印出 10 條數(shù)據(jù):

代碼塊

JSON

@Test

public void streamSortedTest() {

? ? Random random = new Random();

? ? random.ints().limit(10).sorted().forEach(System.out::println);

}

9.compare(排序)

代碼塊

JSON

list.compare((a,b)->a-b); 升序

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容