解讀Java8新特性--lambda的作用
我們期待了很久lambda為java帶來閉包的概念,但是如果我們不在集合中使用它的話,就損失了很大價值。現有介面遷移成為lambda風格的問題已經透過default methods解決了,在這篇文章將深入解析Java集合裡面的批量資料操作解開lambda最強作用的神秘面紗。
我們期待了很久lambda為java帶來閉包的概念,但如果我們不在集合中使用它的話,就損失了很大價值。現有介面遷移成為lambda風格的問題已經透過default methods解決了,在這篇文章將深入解析Java集合裡面的批量資料操作(bulk operation),解開lambda最強作用的神秘面紗。
1.關於JSR335
#JSR是Java Specification Requests的縮寫,意思是Java 規格請求,Java 8 版本的主要改進是Lambda 專案(JSR 335),目的是讓Java 更容易為多核心處理器編寫程式碼。
2.外部VS內部迭代
#以前Java集合是不能夠表達內部迭代的,而只提供了一種外在迭代的方式,也就是for或while迴圈。
List persons = asList(new Person("Joe"), new Person("Jim"), new Person("John")); for (Person p : persons) { p.setLastName("Doe"); }
上面的例子是我們先前的做法,也就是所謂的外部迭代,循環是固定的順序循環。在現在多核心的時代,如果我們想並行循環,不得不修改以上程式碼。效率能有多大提升也說定,且會帶來一定的風險(線程安全問題等等)。
要描述內部迭代,我們需要用到Lambda這樣的類別庫,下面利用lambda和Collection.forEach重寫上面的循環
persons.forEach(p->p.setLastName("Doe"));
現在是由jdk 函式庫來控制循環了,我們不需要關心last name是怎麼被設定到每一個person物件裡面去的,函式庫可以根據運行環境來決定怎麼做,並行,亂序或懶加載方式。這就是內部迭代,客戶端將行為p.setLastName當做資料傳入api裡面。 內部迭代其實和集合的批次操作並沒有密切的聯繫,借助它我們感受到語法表達上的變化。真正有意思的和批量操作相關的是新的流(stream)API。新的java.util.stream套件已經加入JDK 8了。
3.Stream API
#串流(Stream)只代表資料流,並沒有資料結構,所以他遍歷完一次之後便再也無法遍歷(這點在程式設計時候需要注意,不像Collection,遍歷多少次裡面都還有數據),它的來源可以是Collection、array、io等等。
3.1中間與終點方法
#流作用是提供了一個操作大數據接口,讓資料操作更容易和更快。它具有過濾、映射以及減少遍歷數等方法,這些方法分為兩種:中間方法和終端方法,「流」抽像天生就該是持續的,中間方法永遠返回的是Stream,因此如果我們要獲取最終結果的話,必須使用終點操作才能收集流產生的最終結果。區分這兩個方法是看他的回傳值,如果是Stream則是中間方法,否則是終點方法。
簡單介紹下幾個中間方法(filter、map)以及終點方法(collect、sum)
##3.1.1Filter
表達式。
List persons = … Stream personsOver18 = persons.stream().filter(p -> p.getAge() > 18);//过滤18岁以上的人
3.1.2Map
Stream adult= persons .stream() .filter(p -> p.getAge() > 18) .map(new Function() { @Override public Adult apply(Person person) { return new Adult(person);//将大于18岁的人转为成年人 } });
Stream map = persons.stream() .filter(p -> p.getAge() > 18) .map(person -> new Adult(person));
3.1.3Count
int countOfAdult=persons.stream() .filter(p -> p.getAge() > 18) .map(person -> new Adult(person)) .count();
3.1.4Collect
List adultList= persons.stream() .filter(p -> p.getAge() > 18) .map(person -> new Adult(person)) .collect(Collectors.toList());
List adultList = persons .stream() .filter(p -> p.getAge() > 18) .map(person -> new Adult(person)) .collect(Collectors.toCollection(ArrayList::new));
篇幅有限,其他的中间方法和终点方法就不一一介绍了,看了上面几个例子,大家明白这两种方法的区别即可,后面可根据需求来决定使用。
3.2顺序流与并行流
每个Stream都有两种模式:顺序执行和并行执行。
顺序流:
List <Person> people = list.getStream.collect(Collectors.toList());
并行流:
List <Person> people = list.getStream.parallel().collect(Collectors.toList());
顾名思义,当使用顺序方式去遍历时,每个item读完后再读下一个item。而使用并行去遍历时,数组会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。
3.2.1并行流原理:
List originalList = someData; split1 = originalList(0, mid);//将数据分小部分 split2 = originalList(mid,end); new Runnable(split1.process());//小部分执行操作 new Runnable(split2.process()); List revisedList = split1 + split2;//将结果合并
大家对hadoop有稍微了解就知道,里面的 MapReduce 本身就是用于并行处理大数据集的软件框架,其 处理大数据的核心思想就是大而化小,分配到不同机器去运行map,最终通过reduce将所有机器的结果结合起来得到一个最终结果,与MapReduce不同,Stream则是利用多核技术可将大数据通过多核并行处理,而MapReduce则可以分布式的。
3.2.2顺序与并行性能测试对比
如果是多核机器,理论上并行流则会比顺序流快上一倍,下面是测试代码
long t0 = System.nanoTime(); //初始化一个范围100万整数流,求能被2整除的数字,toArray()是终点方法 int a[]=IntStream.range(0, 1_000_000).filter(p -> p % 2==0).toArray(); long t1 = System.nanoTime(); //和上面功能一样,这里是用并行流来计算 int b[]=IntStream.range(0, 1_000_000).parallel().filter(p -> p % 2==0).toArray(); long t2 = System.nanoTime(); //我本机的结果是serial: 0.06s, parallel 0.02s,证明并行流确实比顺序流快 System.out.printf("serial: %.2fs, parallel %.2fs%n", (t1 - t0) * 1e-9, (t2 - t1) * 1e-9);
3.3关于Folk/Join框架
应用硬件的并行性在java 7就有了,那就是 java.util.concurrent 包的新增功能之一是一个 fork-join 风格的并行分解框架,同样也很强大高效,有兴趣的同学去研究,这里不详谈了,相比Stream.parallel()这种方式,我更倾向于后者。
4.总结
如果没有lambda,Stream用起来相当别扭,他会产生大量的匿名内部类,比如上面的3.1.2map例子,如果没有default method,集合框架更改势必会引起大量的改动,所以lambda+default method使得jdk库更加强大,以及灵活,Stream以及集合框架的改进便是最好的证明。
以上是解讀Java8新特性--lambda的作用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

nohup的作用及原理解析在Unix和類Unix作業系統中,nohup是一個常用的命令,用於在後台運行命令,即便用戶退出當前會話或關閉終端窗口,命令仍然能夠繼續執行。在本文中,我們將詳細解析nohup指令的作用和原理。一、nohup的作用後台運行命令:透過nohup命令,我們可以讓需要長時間運行的命令在後台持續執行,而不受用戶退出終端會話的影響。這在需要運行

Win11系統下如何顯示檔案後綴?詳細解讀在Windows11作業系統中,檔案後綴是指檔案名稱後面的點及其後面的字符,用來表示檔案的類型。在預設情況下,Windows11系統會隱藏檔案的後綴,這樣在檔案總管中只能看到檔案的名稱而無法直觀地了解檔案的類型。然而,對於某些使用者來說,顯示文件後綴是非常必要的,因為它能幫助他們更好地辨識文件類型以及進行相關操

理解LinuxDTS的作用及用法在嵌入式Linux系統開發中,設備樹(DeviceTree,簡稱DTS)是一種描述硬體設備及其在系統中的連接關係和屬性的資料結構。設備樹使得Linux核心能夠在不同的硬體平台上靈活地運行,而無需對核心進行修改。在本文中,將介紹LinuxDTS的作用及用法,並提供具體的程式碼範例來幫助讀者更好地理解。 1.設備樹的作用設備樹

PHP中define函數的重要性與作用1.define函數的基本介紹在PHP中,define函數是用來定義常數的關鍵函數,常量在程式運行過程中不會改變其值。利用define函數定義的常數,在整個腳本中均可被訪問,具有全域性。 2.define函數的語法define函數的基本語法如下:define("常數名稱","常數值&qu

PHP是一種廣泛應用於Web開發的伺服器端腳本語言,它主要的功能是產生動態網頁內容,與HTML結合使用,可以創造出豐富多彩的網頁。 PHP的功能強大,它可以執行各種資料庫操作、檔案操作、表單處理等任務,為網站提供強大的互動性和功能性。在接下來的文章中,我們將進一步探究PHP的作用與功能,並配以詳細的程式碼範例。首先,我們來看看PHP的常見用途:動態網頁生成:P

在Golang(Go語言)中並沒有傳統意義上的類別的概念,但它提供了一種稱為結構體的資料類型,透過結構體可以實現類似類別的物件導向特性。在本文中,我們將介紹如何使用結構體實現物件導向的特性,並提供具體的程式碼範例。結構體的定義和使用首先,讓我們來看看結構體的定義和使用方式。在Golang中,結構體可以透過type關鍵字定義,然後在需要的地方使用。結構體中可以包含屬

LinuxBashrc是Linux系統中的一個設定文件,用於設定使用者的Bash(BourneAgainShell)環境。 Bashrc檔案儲存了使用者登入時所需的環境變數、啟動腳本等訊息,可以客製化使用者的Shell環境。在Linux系統中,每個使用者都有一個對應的Bashrc文件,位於使用者的家目錄下的隱藏資料夾中。 Bashrc檔案的作用主要有以下幾點:設定環

PHP函數透過封裝程式碼、提高可讀性、增強可維護性、減少重複,可簡化程式碼。實戰案例包括列印值、執行數學運算、處理字串、操作陣列以及建立自訂函數。
