摘要:第四章引入流一什么是流流是的新成員,它允許你以聲明性方式處理數(shù)據(jù)集合通過(guò)查詢語(yǔ)句來(lái)表達(dá),而不是臨時(shí)編寫(xiě)一個(gè)實(shí)現(xiàn)。
第四章 引入流 一、什么是流
流是Java API的新成員,它允許你以聲明性方式處理數(shù)據(jù)集合(通過(guò)查詢語(yǔ)句來(lái)表達(dá),而不是臨時(shí)編寫(xiě)一個(gè)實(shí)現(xiàn))。就現(xiàn)在來(lái)說(shuō),你可以把它們看成遍歷數(shù)據(jù)集的高級(jí)迭代器。此外,流還可以透明地并行處理,你無(wú)需寫(xiě)任何多線程代碼。
下面兩段代碼都是用來(lái)返回低熱量的菜肴名稱的,并按照卡路里排序,一個(gè)是用Java 7寫(xiě)的,另一個(gè)是用Java 8的流寫(xiě)的。
之前(Java 7):
ListlowCaloricDishes = new ArrayList<>(); for(Dish d: menu){ if(d.getCalories() < 400){ lowCaloricDishes.add(d); } } Collections.sort(lowCaloricDishes, new Comparator () { public int compare(Dish d1, Dish d2){ return Integer.compare(d1.getCalories(), d2.getCalories()); } }); List lowCaloricDishesName = new ArrayList<>(); for(Dish d: lowCaloricDishes){ lowCaloricDishesName.add(d.getName()); }
在這段代碼中,你用了一個(gè)“垃圾變量”lowCaloricDishes。它唯一的作用就是作為一次
性的中間容器。在Java 8中,實(shí)現(xiàn)的細(xì)節(jié)被放在它本該歸屬的庫(kù)里了。
之后(Java 8):
import static java.util.Comparator.comparing; import static java.util.stream.Collectors.toList; ListlowCaloricDishesName = menu.stream() .filter(d -> d.getCalories() < 400) .sorted(comparing(Dish::getCalories)) .map(Dish::getName) .collect(toList());
為了利用多核架構(gòu)并行執(zhí)行這段代碼,你只需要把stream()換成parallelStream():
ListlowCaloricDishesName = menu.parallelStream() .filter(d -> d.getCalories() < 400) .sorted(comparing(Dishes::getCalories)) .map(Dish::getName) .collect(toList());
按照Map里面的類別對(duì)菜肴進(jìn)行分組。
Map> dishesByType = menu.stream().collect(groupingBy(Dish::getType));
其他庫(kù):Guava、Apache和lambdaj
為了給Java程序員提供更好的庫(kù)操作集合,前人已經(jīng)做過(guò)了很多嘗試。比如,Guava就是谷歌創(chuàng)建的一個(gè)很流行的庫(kù)。它提供了multimaps和multisets等額外的容器類。Apache Commons Collections庫(kù)也提供了類似的功能。Mario Fusco編寫(xiě)的lambdaj受到函數(shù)式編程的啟發(fā),也提供了很多聲明性操作集合的工具。
流到底是什么呢?簡(jiǎn)短的定義就是“從支持?jǐn)?shù)據(jù)處理操作的源生成的元素序列”。
元素序列——就像集合一樣,流也提供了一個(gè)接口,可以訪問(wèn)特定元素類型的一組有序值。因?yàn)榧鲜菙?shù)據(jù)結(jié)構(gòu),所以它的主要目的是以特定的時(shí)間/空間復(fù)雜度存儲(chǔ)和訪問(wèn)元素(如ArrayList 與 LinkedList)。但流的目的在于表達(dá)計(jì)算,比如你前面見(jiàn)到的filter、sorted和map。集合講的是數(shù)據(jù),流講的是計(jì)算。我們會(huì)在后面幾節(jié)中詳細(xì)解釋這個(gè)思想。
源——流會(huì)使用一個(gè)提供數(shù)據(jù)的源,如集合、數(shù)組或輸入/輸出資源。 請(qǐng)注意,從有序集合生成流時(shí)會(huì)保留原有的順序。由列表生成的流,其元素順序與列表一致。
數(shù)據(jù)處理操作——流的數(shù)據(jù)處理功能支持類似于數(shù)據(jù)庫(kù)的操作,以及函數(shù)式編程語(yǔ)言中的常用操作,如filter、map、reduce、find、match、sort等。流操作可以順序執(zhí)行,也可并行執(zhí)行。
eg: 選出3條卡路里高于300的菜肴的菜肴的名字
import static java.util.stream.Collectors.toList; List二、流與集合threeHighCaloricDishNames = menu.stream() .filter(d -> d.getCalories() > 300) .map(Dish::getName) .limit(3) //篩選(filter)、提?。╩ap)或截?cái)啵╨imit) .collect(toList()); System.out.println(threeHighCaloricDishNames); //在調(diào)用collect之前,沒(méi)有任何結(jié)果產(chǎn)生,實(shí)際上根本就沒(méi)有從menu里選擇元素
和迭代器類似,流只能遍歷一次。遍歷完之后,我們就說(shuō)這個(gè)流已經(jīng)被消費(fèi)掉了。
使用Collection接口需要用戶去做迭代(比如用for-each),這稱為外部迭代。 相反,Streams庫(kù)使用內(nèi)部迭代——它幫你把迭代做了,還把得到的流值存在了某個(gè)地方,你只要給出一個(gè)函數(shù)說(shuō)要干什么就可以了。
三、流操作java.util.stream.Stream中的Stream接口定義了許多操作。它們可以分為兩大類:
中間操作
可以連接起來(lái)的流操作稱為中間操作,諸如filter或sorted等終端操作
關(guān)閉流的操作稱為終端操作,其結(jié)果是任何不是流的值,比如List、Integer,甚至void
eg:(注意循環(huán)合并)
Listnames = menu.stream() .filter(d -> { System.out.println("filtering" + d.getName()); return d.getCalories() > 300; }) .map(d -> { System.out.println("mapping" + d.getName()); return d.getName(); }) .limit(3) .collect(toList()); System.out.println(names);
此代碼執(zhí)行時(shí)將打?。?/p>
filtering pork mapping pork filtering beef mapping beef filtering chicken mapping chicken [pork, beef, chicken]
盡管filter和map是兩個(gè)獨(dú)立的操作,但它們合并到同一次遍歷中了(我們把這種技術(shù)叫作循環(huán)合并)。
四、使用流流的使用一般包括三件事:
一個(gè)數(shù)據(jù)源(如集合)來(lái)執(zhí)行一個(gè)查詢;
一個(gè)中間操作鏈,形成一條流的流水線;
一個(gè)終端操作,執(zhí)行流水線,并能生成結(jié)果。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/77531.html
摘要:實(shí)戰(zhàn)讀書(shū)筆記第一章從方法傳遞到接著上次的,繼續(xù)來(lái)了解一下,如果繼續(xù)簡(jiǎn)化代碼。去掉并且生成的數(shù)字是萬(wàn),所消耗的時(shí)間循序流并行流至于為什么有時(shí)候并行流效率比循序流還低,這個(gè)以后的文章會(huì)解釋。 《Java8實(shí)戰(zhàn)》-讀書(shū)筆記第一章(02) 從方法傳遞到Lambda 接著上次的Predicate,繼續(xù)來(lái)了解一下,如果繼續(xù)簡(jiǎn)化代碼。 把方法作為值來(lái)傳遞雖然很有用,但是要是有很多類似與isHeavy...
摘要:比如,你可以建立一個(gè),選出熱量超過(guò)卡路里的頭三道菜請(qǐng)注意也可以用在無(wú)序流上,比如源是一個(gè)。跳過(guò)元素流還支持方法,返回一個(gè)扔掉了前個(gè)元素的流。一般來(lái)說(shuō),應(yīng)該使用來(lái)對(duì)這種流加以限制,以避免打印無(wú)窮多個(gè)值。 一、篩選和切片 1.用謂詞篩選 Streams接口支持filter方法。該操作會(huì)接受一個(gè)謂詞(一個(gè)返回boolean的函數(shù))作為參數(shù),并返回一個(gè)包括所有符合謂詞的元素的流。例如篩選出所有...
摘要:正確使用并行流錯(cuò)用并行流而產(chǎn)生錯(cuò)誤的首要原因,就是使用的算法改變了某些共享狀態(tài)。高效使用并行流留意裝箱有些操作本身在并行流上的性能就比順序流差還要考慮流的操作流水線的總計(jì)算成本。 一、并行流 1.將順序流轉(zhuǎn)換為并行流 對(duì)順序流調(diào)用parallel方法: public static long parallelSum(long n) { return Stream.iterate(1L...
摘要:跳過(guò)元素流還支持方法,返回一個(gè)扔掉了前個(gè)元素的流。歸約到目前為止,我們見(jiàn)到過(guò)的終端操作都是返回一個(gè)之類的或?qū)ο蟮取_@樣的查詢可以被歸類為歸約操作將流歸約成一個(gè)值。通過(guò)反復(fù)使用加法,你把一個(gè)數(shù)字列表歸約成了一個(gè)數(shù)字。 使用流 在上一篇的讀書(shū)筆記中,我們已經(jīng)看到了流讓你從外部迭代轉(zhuǎn)向內(nèi)部迭代。這樣,你就用不著寫(xiě)下面這樣的代碼來(lái)顯式地管理數(shù)據(jù)集合的迭代(外部迭代)了: /** * 菜單 ...
摘要:收集器用作高級(jí)歸約剛剛的結(jié)論又引出了優(yōu)秀的函數(shù)式設(shè)計(jì)的另一個(gè)好處更易復(fù)合和重用。更具體地說(shuō),對(duì)流調(diào)用方法將對(duì)流中的元素觸發(fā)一個(gè)歸約操作由來(lái)參數(shù)化。另一個(gè)常見(jiàn)的返回單個(gè)值的歸約操作是對(duì)流中對(duì)象的一個(gè)數(shù)值字段求和。 用流收集數(shù)據(jù) 我們?cè)谇耙徽轮袑W(xué)到,流可以用類似于數(shù)據(jù)庫(kù)的操作幫助你處理集合。你可以把Java 8的流看作花哨又懶惰的數(shù)據(jù)集迭代器。它們支持兩種類型的操作:中間操作(如 filt...
摘要:線程允許同一個(gè)進(jìn)程中同時(shí)存在多個(gè)程序控制流。線程也被稱為輕量級(jí)進(jìn)程?,F(xiàn)代操作系統(tǒng)中,都是以線程為基本的調(diào)度單位,而不是進(jìn)程。 并發(fā)簡(jiǎn)史 在早期的計(jì)算機(jī)中不包含操作系統(tǒng),從頭至尾都只執(zhí)行一個(gè)程序,并且這個(gè)程序能訪問(wèn)計(jì)算機(jī)所有資源。操作系統(tǒng)的出現(xiàn)使得計(jì)算機(jī)每次能運(yùn)行多個(gè)程序,并且不同的程序都在單獨(dú)的進(jìn)程中運(yùn)行:操作系統(tǒng)為各個(gè)獨(dú)立執(zhí)行的進(jìn)程分配內(nèi)存、文件句柄、安全證書(shū)等。不同進(jìn)程之間通過(guò)一些...
閱讀 1373·2023-04-25 19:33
閱讀 1240·2021-10-21 09:39
閱讀 3710·2021-09-09 09:32
閱讀 2714·2019-08-30 10:58
閱讀 1721·2019-08-29 16:17
閱讀 930·2019-08-29 15:29
閱讀 2961·2019-08-26 11:55
閱讀 2724·2019-08-26 10:33