摘要:流的使用一般包括三件事一個數(shù)據(jù)源來執(zhí)行一個查詢一個中間操作鏈,形成一條流水線一個終端操作,執(zhí)行流水線并生成結(jié)果以上便是流的一些基礎(chǔ)知識,下一章會更加深入理解流。實(shí)戰(zhàn)第四章引入流讀書筆記歡迎加入咖啡館的春天。
流是什么
幾乎每個 Java 應(yīng)用都會制造和處理集合。流 允許我們以聲明性方式處理集合(通過類似于 SQL 查詢語句來表達(dá),而不是臨時寫一個實(shí)現(xiàn))。此外 流 還可以透明地并行處理,無需寫任何多線程代碼。
先看一個例子,混混眼熟就行
Listresult = dishList .parallelStream() // 過濾 .filter(d -> d.getCalories() < 400) // 排序 .sorted(Comparator.comparing(Dish::getCalories)) // 映射 .map(Dish::getName) // 保存 .collect(Collectors.toList());
而且以 parallelStream 調(diào)用會利用多核架構(gòu)并行執(zhí)行這段代碼,如果想要單線程處理,只需要把 parallelStream 換成 stream。
從代碼可以看出,它是以聲明性方式寫的:filter、sorted、map 和 collect。如同 SQL 中的 SELECT、FROM、WHERE 一樣。
Java 8中的 Stream API 可以
聲明性:更簡潔
可復(fù)合:更靈活
可并行:性能更好
流簡介流的定義是 從支持?jǐn)?shù)據(jù)處理操作的源生成的元素序列。
元素序列:流提供了一個接口,可以訪問特定元素類型的一組有序值
源:流會使用一個提供數(shù)據(jù)的源,如集合、數(shù)組或輸出/輸出
數(shù)據(jù)處理操作:流的數(shù)據(jù)處理功能支持類似數(shù)據(jù)庫的聲明式操作,可以串行處理也可并行
流水線:很多流操作本身會返回一個流,這樣多個操作就可以鏈接起來,形成一個大的流水線
內(nèi)部迭代:與使用迭代器顯式迭代不同,流的迭代操作是在背后執(zhí)行的
為了更直觀地理解流以及 Lambda 在其的應(yīng)用,我們可以先創(chuàng)建一個菜肴類
public class Dish { // 名字 private String name; // 是否素食 private Boolean vegetarian; // 卡路里 private Integer calories; // 類型 private Type type; public Dish(String name, Boolean vegetarian, Integer calories, Type type) { this.name = name; this.vegetarian = vegetarian; this.calories = calories; this.type = type; } // 類型:肉、魚、其他 public enum Type { MEAT, FISH, OTHER } // Getter and Setter }
然后用構(gòu)造函數(shù)定義一個菜單 List,好讓我們對其進(jìn)行流的演示
Listmenu = new ArrayList<>(); // 豬肉:非素食,800卡路里,肉類 menu.add(new Dish("pork", false, 800, Dish.Type.MEAT)); // 牛肉:非素食,700卡路里,肉類 menu.add(new Dish("beef", false, 700, Dish.Type.MEAT)); // 米飯:素食,359卡路里,其他 menu.add(new Dish("rice", true, 350, Dish.Type.OTHER)); // 披薩:素食,550卡路里,其他 menu.add(new Dish("pizza", true, 550, Dish.Type.OTHER)); // 對蝦:非素食,350卡路里,魚類 menu.add(new Dish("prawns", false, 350, Dish.Type.FISH)); // 三文魚:非素食,450卡路里,魚類 menu.add(new Dish("salmon", false, 450, Dish.Type.FISH));
接下來我們使用流找出頭三個高熱量菜肴的名字
ListthreeHighCaloriesDishNames = menu // 從 menu 獲得源 .stream() // Lambda 調(diào)用謂詞函數(shù)式接口過濾卡路里大于400的高熱量菜肴 .filter((dish) -> dish.getCalories() > 400) // 將過濾結(jié)果映射成對應(yīng)的菜肴名 .map(Dish::getName) // 按照順序選擇三個 .limit(3) // 保存成 List .collect(Collectors.toList());
其中兩個 Lambda 對應(yīng)的是以下的快捷寫法
// 返回一個判斷卡路里是否高于400的謂詞接口對象 PredicatedishPredicate = (Dish dish) -> dish.getCalories() > 400; // 返回一個映射菜肴名稱的映射接口對象 Function dishStringFunction = (Dish dish) -> dish.getName();
如果看不懂請回顧上兩章內(nèi)容。涉及到行為參數(shù)化和 Lambda 的多種可簡寫方式。
在這個小小的例子里,有很多概念。我們先是對 menu 調(diào)用 stream 方法得到一個流,所以可以稱 menu 為 源。它給流提供一個 元素序列,接下來對流進(jìn)行的一系列 數(shù)據(jù)處理操作 都會返回另一個流:filter、 map、limit,這樣它們就可以拼接成一條 流水線。最后 collect 操作開始處理流水線,并返回結(jié)果。在調(diào)用 collect 之前沒有任何結(jié)果產(chǎn)生,實(shí)際上根本就沒有從 menu 里選擇元素。可以這么說,在流水線里的方法調(diào)用都在排隊(duì)等待,直到調(diào)用 collect。
流與集合粗略地說,流與集合之間的差異就在于什么時候進(jìn)行計(jì)算。流是在概念上固定的數(shù)據(jù)結(jié)構(gòu),其元素則是按需計(jì)算的。例如,盡管質(zhì)數(shù)有無窮多個,但我們僅僅需要從流中提取需要的值,而這些值只會按需生成。與此相反,集合想要創(chuàng)建一個包含所有質(zhì)數(shù)的集合,那會計(jì)算起來沒完沒了,因?yàn)榭傆行碌馁|(zhì)數(shù)要計(jì)算,這樣我們就不能從中取得需要的值。
和迭代器一樣,流只能遍歷一次,遍歷完后我們就可以說這個流被消費(fèi)掉了。我們可以從源再獲得一個新的流來重新遍歷。
用同一個流遍歷 menu 兩次會拋出異常
Stream外部迭代與內(nèi)部迭代dishStream = menu.stream(); // 等同于 dishStream.forEach((Dish dish) -> System.out.println(dish)); dishStream.forEach(System.out::println); // java.lang.IllegalStateException: stream has already been operated upon or closed // 流已經(jīng)被操作或關(guān)閉 dishStream.forEach(System.out::println);
集合需要我們手動去做迭代,比如 for-each,這樣被稱為外部迭代。相反,流使用內(nèi)部迭代。
集合:使用 for-each 循環(huán)外部迭代
ListdishNames = new ArrayList<>(); for (Dish dish : menu) { dishNames.add(dish.getName()); }
流:內(nèi)部迭代
ListdishNames = menu .stream() .map(Dish::getName) .collect(Collectors.toList());
乍一看好像沒有多大的區(qū)別,但是如果考慮到并行處理呢?如果使用外部迭代則需要我們很痛苦地自己去處理并行,而用流則非常簡單,只需要把 stream 換成 parallelStream。
流的使用一般包括三件事:
一個數(shù)據(jù)源來執(zhí)行一個查詢
一個中間操作鏈,形成一條流水線
一個終端操作,執(zhí)行流水線并生成結(jié)果
以上便是流的一些基礎(chǔ)知識,下一章會更加深入理解流。
Java 8 實(shí)戰(zhàn) 第四章 引入流 讀書筆記
歡迎加入咖啡館的春天(338147322)。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/70217.html
摘要:第四章引入流一什么是流流是的新成員,它允許你以聲明性方式處理數(shù)據(jù)集合通過查詢語句來表達(dá),而不是臨時編寫一個實(shí)現(xiàn)。 第四章 引入流 一、什么是流 流是Java API的新成員,它允許你以聲明性方式處理數(shù)據(jù)集合(通過查詢語句來表達(dá),而不是臨時編寫一個實(shí)現(xiàn))。就現(xiàn)在來說,你可以把它們看成遍歷數(shù)據(jù)集的高級迭代器。此外,流還可以透明地并行處理,你無需寫任何多線程代碼。 下面兩段代碼都是用來返回低...
摘要:內(nèi)部迭代與使用迭代器顯式迭代的集合不同,流的迭代操作是在背后進(jìn)行的。流只能遍歷一次請注意,和迭代器類似,流只能遍歷一次。 流(Stream) 流是什么 流是Java API的新成員,它允許你以聲明性方式處理數(shù)據(jù)集合(通過查詢語句來表達(dá),而不是臨時編寫一個實(shí)現(xiàn))。就現(xiàn)在來說,你可以把它們看成遍歷數(shù)據(jù)集的高級迭代器。此外,流還可以透明地并行處理,你無需寫任何多線程代碼了!我會在后面的筆記中...
摘要:異步文件系統(tǒng)不會阻塞程序的執(zhí)行,而是在操作完成時,通過回調(diào)函數(shù)將結(jié)果返回。 文件系統(tǒng)(File System): 在Node中,文件系統(tǒng)的交互是非常重要的,服務(wù)器的本質(zhì)就是將本地的文件發(fā)送給客戶端, Node通過fs模塊來和文件系統(tǒng)進(jìn)行交互,該模塊提供了一些標(biāo)準(zhǔn)的文件訪問API類打開、讀取、寫入文件、以及與其交互。 要是用fs模塊,首先要從核心模塊中加載; 使用 const fs= ...
摘要:新特性總覽標(biāo)簽本文主要介紹的新特性,包括表達(dá)式方法引用流默認(rèn)方法組合式異步編程新的時間,等等各個方面。還有對應(yīng)的和類型的函數(shù)連接字符串廣義的歸約匯總起始值,映射方法,二元結(jié)合二元結(jié)合。使用并行流時要注意避免共享可變狀態(tài)。 Java8新特性總覽 標(biāo)簽: java [TOC] 本文主要介紹 Java 8 的新特性,包括 Lambda 表達(dá)式、方法引用、流(Stream API)、默認(rèn)方...
閱讀 3602·2021-11-24 10:25
閱讀 2508·2021-11-24 09:38
閱讀 1217·2021-09-08 10:41
閱讀 2903·2021-09-01 10:42
閱讀 2569·2021-07-25 21:37
閱讀 1981·2019-08-30 15:56
閱讀 914·2019-08-30 15:55
閱讀 2749·2019-08-30 15:54