摘要:本章是該書的第五章主要講了方法引用和收集器方法引用形如這樣的表達式可以簡寫為這種簡寫的語法被稱為方法引用方法引用無需考慮參數因為一個方法引用可以在不同的情況下解析為不同的表達式這依賴于的推斷方法引用的類型方法引用可以分為四類引用靜態方法
本章是該書的第五章, 主要講了方法引用和收集器
方法引用形如:
artist -> artist.getName() (String arg) -> arg.length()
這樣的表達式, 可以簡寫為:
Artist::getName String::length
這種簡寫的語法被稱為方法引用. 方法引用無需考慮參數, 因為一個方法引用可以在不同的情況下解析為不同的Lambda表達式, 這依賴于JVM的推斷.
方法引用的類型方法引用可以分為四類:
引用靜態方法: ClassName::staticMethodName, 比如: String.valueOf
引用特定實例方法: object::instanceMethodName, 比如: str::toString
引用特定類型的任意對象的實例方法: ClassName::instanceMethodName, 比如: String::length
引用構造方法: ClassName::new, 比如: String::new
元素順序當我們對集合進行操作時, 有時希望是按照一定的順序來操作, 而有時又希望是亂序的操作. 有兩個方法可以幫助我們進行順序的操作.
亂序BaseStream.unordered()方法可以打亂順序, 科技將本來有序的集合變成無序的集合
排序Stream.sorted方法有兩個簽名, 一個無參, 一個有參數Comparator super T> comparator
無參的方法要求T實現了Comparable接口
有參方法需要提供一個比較器
收集器收集器是一種通用的, 從流中生成復雜值的結構. 將其傳給collect方法, 所有的流就都可以使用它. 而下面提到的單個收集器, 都可以使用reduce方法模擬.
轉換成集合我們可以使用Collectors中的靜態方法toList() toSet()等, 將流收集為List或Set
stream.collect(toList()) stream.collect(toSet())
我們不需要關心具體使用的是哪一種具體的實現, Stream類庫會為我們選擇. 因為我們可以利用Stream進行并行數據處理, 所以選擇是否線程安全的集合十分重要.
當然我們也可以指定使用哪一種實現來進行收集:
stream.collect(toCollection(ArrayList::new))轉換成值
Collectors類提供了很多的方法用于轉化值, 比如counting maxBy minBy等等, 可以查看javadoc了解.
目前了解到的是, 這三個方法都可以使用Stream中的count max min方法代替, 而不需要作為collect方法的參數
數據分割有時我們想按照一個條件把數據分成兩個部分, 而不是只獲取符合條件的部分, 這時可以使用partitioningBy方法收集. 將它傳入collect方法, 可以得到一個Map
groupingBy方法可以將流分成多個List, 而不僅僅是兩個, 接收一個Lambda表達式作為參數, 其返回值作為key, 最后的結果也是一個Map, 形如Map
如果要從流中得到字符串, 可以在得到Stream
artists.stream() .map(Artist::getName) .collect(Collectors.joining(",", "[", "]"));組合收集器
我們可以將收集器組合起來, 達到更強的功能. 書上舉了兩個栗子
例一
public MapnumberOfAlbums(Stream albums) { return albums .collect( groupingBy(Album::getMainMusicina, counting())); }
這個方法的目的是統計每個歌手的作品數目. 如果不組合收集器, 我們先用groupingBy得到一個Map
上面的counting方法類似于count方法, 作用于List
例二
public Map> nameOfAlbums(Stream albums) { return albums .collect( groupingBy(Album::getMainMusician, mapping(Album::getName, toList()))); }
這個方法的目的是得到每個歌手的作品名稱列表. 如果不組合收集器, 我們將會先得到一個Map
mapping收集器的功能類似于map, 將一種類型的流轉換成另一種類型. 所以類似的, mapping并不知道要把結果收集成什么數據結構, 它的第二個參數就會接收一個普通的收集器, 比如這里的toList, 來完成收集.
這里的counting和mapping是我們用到的第二個收集器, 用于收集最終結果的一個子集, 這些收集器叫做下游收集器.
定制收集器定制收集器看起來麻煩, 其實抓住要點就行了.
使用reduce方法前面說過, 這些收集器都可以使用reduce方法實現, 我們定制收集器, 實際上就是為reduce方法編寫三個參數, 分別是:
identity
accumulator
combiner
關于這三個參數的意義, 如果不太理解, 可以看看這個答案: https://segmentfault.com/q/1010000004944450
我們可以設計一個類, 為這三個參數設計三個方法, 再提供一個方法用于獲取目標類型(如果這個類就是目標類型的話, 可以不提供這個方法)
實現Collector接口如果不想顯式的使用reduce方法, 我們只需要提供一個類, 實現Collector接口.
該接口需要三個泛型參數, 依次是:
待收集元素的類型
累加器的類型
最終結果的類型
需要實現的方法有:
supplier: 生成初始容器
accumulator: 累加計算方法
combiner: 在并發流中合并容器
finisher: 將容器轉換成最終值
characteristics: 獲取特征集合
多數情況下, 我們的容器器和我們的目標類型并不一致, 這時, 需要實現finisher方法將容器轉化為目標類型, 比如調用容器的toString方法.
有時我們的目標類型就是我們的容器, finisher方法就不需要對容器做任何操作, 而是通過設置characteristics為IDENTITY_FINISH, 使用框架提供的優化得到結果.
詳細講解可以參見http://irusist.github.io/2016/01/04/Java-8%E4%B9%8BCollector/
Map新增方法Java 8為Map新增了很多方法, 可以通過搜索引擎輕松找到相關文章. 這里舉幾個書中提到的相關方法.
V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction)
V computeIfPresent(K key, BiFunction super K, ? super V, extends V> remappingFunction)
V compute(K key, BiFunction super K, ? super V, ? extends V> remappingFunction)
這三個方法類似, 都是根據key來處理, 只是Lambda表達式的執行條件不同, 從函數名就可以看出來. 不過要注意Lambda表達式的參數, 第一個方法的Lambda只需要一個參數key, 后面兩個方法的Lambda需要兩個參數key和value, 而compute方法的Lambda中的value參數可能為null.
V merge(K key, V value, BiFunction super V, ? super V, ? extends V> remappingFunction)
此方法用于合并value, 新value在第二個參數給出. Lambda表達式規定合并方法, 其兩個參數依次是oldValue和newValue, oldValue是原Map的value, 可能為空; newValue為merge方法的第二個參數.
void forEach(BiConsumer super K, ? super V> action)
通過forEach方法, 不再需要使用外部迭代來遍歷Map.
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/66626.html
摘要:收集器用作高級歸約剛剛的結論又引出了優秀的函數式設計的另一個好處更易復合和重用。更具體地說,對流調用方法將對流中的元素觸發一個歸約操作由來參數化。另一個常見的返回單個值的歸約操作是對流中對象的一個數值字段求和。 用流收集數據 我們在前一章中學到,流可以用類似于數據庫的操作幫助你處理集合。你可以把Java 8的流看作花哨又懶惰的數據集迭代器。它們支持兩種類型的操作:中間操作(如 filt...
摘要:第四章引入流一什么是流流是的新成員,它允許你以聲明性方式處理數據集合通過查詢語句來表達,而不是臨時編寫一個實現。 第四章 引入流 一、什么是流 流是Java API的新成員,它允許你以聲明性方式處理數據集合(通過查詢語句來表達,而不是臨時編寫一個實現)。就現在來說,你可以把它們看成遍歷數據集的高級迭代器。此外,流還可以透明地并行處理,你無需寫任何多線程代碼。 下面兩段代碼都是用來返回低...
摘要:本文是函數式編程第三章的讀書筆記,章名為流。正確使用表達式明確要達成什么轉化,而不是說明如何轉化沒有副作用只通過函數的返回值就能充分理解函數的全部作用函數不會修改程序或外界的狀態獲取值而不是變量避免使用數組逃過的追殺,應該考慮優化邏輯 本文是「Java 8 函數式編程」第三章的讀書筆記,章名為流。本章主要介紹了外部迭代與內部迭代以及常用的高階函數。 外部迭代與內部迭代 外部迭代 過去我...
摘要:新特性總覽標簽本文主要介紹的新特性,包括表達式方法引用流默認方法組合式異步編程新的時間,等等各個方面。還有對應的和類型的函數連接字符串廣義的歸約匯總起始值,映射方法,二元結合二元結合。使用并行流時要注意避免共享可變狀態。 Java8新特性總覽 標簽: java [TOC] 本文主要介紹 Java 8 的新特性,包括 Lambda 表達式、方法引用、流(Stream API)、默認方...
摘要:而面向對象則是向程序員提供表示問題空間中元素的工具,我們將問題空間中的元素及其在解空間中的表示稱為對象。為什么要把對象看作是服務提供者呢這是將問題分解為對象集合的一種合理方式。職能太多,可能會導致對象的內聚性降低。在試圖將子類對象當作其基類 計算機是頭腦延伸的工具,是一種不同類型的表達媒體。本文以背景性的和補充性的材料,介紹包括開發方法概述在內的面向對象程序設計(Object-orie...
閱讀 733·2021-11-17 09:33
閱讀 3766·2021-09-01 10:46
閱讀 1758·2019-08-30 11:02
閱讀 3288·2019-08-29 15:05
閱讀 1404·2019-08-26 11:39
閱讀 2280·2019-08-23 17:04
閱讀 1980·2019-08-23 15:43
閱讀 1377·2019-08-23 14:12