java8 stream 注意點


https://blog.csdn.net/lixiaobuaa/article/details/81099838

 

首先,Stream流有一些特性:

  1. Stream流不是一種數據結構,不保存數據,它只是在原數據集上定義了一組操作。//特別注意
  2. 這些操作是惰性的,即每當訪問到流中的一個元素,才會在此元素上執行這一系列操作。
  3. Stream不保存數據,故每個Stream流只能使用一次

關於應用在Stream流上的操作,可以分成兩種:Intermediate(中間操作)和Terminal(終止操作)。中間操作的返回結果都是Stream,故可以多個中間操作疊加;終止操作用於返回我們最終需要的數據,只能有一個終止操作。至於哪些方法是中間操作,哪些方法是終止操作,我們一會兒再說。

使用Stream流,可以清楚地知道我們要對一個數據集做何種操作,可讀性強。而且可以很輕松地獲取並行化Stream流,不用自己編寫多線程代碼,可以讓我們更加專注於業務邏輯。

接下來看一下Stream流的接口繼承關系:


基礎接口BaseStream<T, S extends BaseStream<T, S>>包含如下方法:

Iterator<T> iterator();

Spliterator<T> spliterator();

boolean isParallel(); //判斷是否是並行化流

S sequential(); //將流串行化

S parallel(); //將流並行化

S unordered(); //解除有序流的順序限制,發揮並行處理的性能優勢

S onClose(Runnable closeHandler);

void close();

默認情況下,從有序集合、生成器、迭代器產生的流或者通過調用Stream.sorted產生的流都是有序流,有序流在並行處理時會在處理完成之后恢復原順序。unordered()方法可以解除有序流的順序限制,更好地發揮並行處理的性能優勢,例如distinct將保存任意一個唯一元素而不是第一個,limit將保留任意n個元素而不是前n個。

BaseStream的四個子接口方法都差不多,只是IntStream、LongStream、DoubleStream直接存儲基本類型,可以避免自動裝/拆箱,效率會更高一些。下面以Stream為例,將接口的方法分類講解一下。

一、 流的生成方法

Collection接口的stream()或parallelStream()方法
靜態的Stream.of()、Stream.empty()方法
Arrays.stream(array, from, to)
靜態的Stream.generate()方法生成無限流,接受一個不包含引元的函數
靜態的Stream.iterate()方法生成無限流,接受一個種子值以及一個迭代函數
Pattern接口的splitAsStream(input)方法
靜態的Files.lines(path)、Files.lines(path, charSet)方法
靜態的Stream.concat()方法將兩個流連接起來
……
注意,無限流的存在,側面說明了流是惰性的,即每當用到一個元素時,才會在這個元素上執行這一系列操作。

二、 流的Intermediate方法(中間操作)

filter(Predicate)
將結果為false的元素過濾掉
map(fun)
轉換元素的值,可以用方法引元或者lambda表達式
flatMap(fun)
若元素是流,將流攤平為正常元素,再進行元素轉換
limit(n)
保留前n個元素
skip(n)
跳過前n個元素
distinct()
剔除重復元素
sorted()
將Comparable元素的流排序
sorted(Comparator)
將流元素按Comparator排序
peek(fun)
流不變,但會把每個元素傳入fun執行,可以用作調試
三、 流的Terminal方法(終結操作)

約簡操作

max(Comparator)
min(Comparator)
count()
findFirst()
返回第一個元素
findAny()
返回任意元素
anyMatch(Predicate)
任意元素匹配時返回true
allMatch(Predicate)
所有元素匹配時返回true
noneMatch(Predicate)
沒有元素匹配時返回true
reduce(fun)
從流中計算某個值,接受一個二元函數作為累積器,從前兩個元素開始持續應用它,累積器的中間結果作為第一個參數,流元素作為第二個參數
reduce(a, fun)
a為幺元值,作為累積器的起點
reduce(a, fun1, fun2)
與二元變形類似,並發操作中,當累積器的第一個參數與第二個參數都為流元素類型時,可以對各個中間結果也應用累積器進行合並,但是當累積器的第一個參數不是流元素類型而是類型T的時候,各個中間結果也為類型T,需要fun2來將各個中間結果進行合並
收集操作

iterator()
forEach(fun)
forEachOrdered(fun)
可以應用在並行流上以保持元素順序
toArray()
toArray(T[] :: new)
返回正確的元素類型
collect(Collector)
collect(fun1, fun2, fun3)
fun1轉換流元素;fun2為累積器,將fun1的轉換結果累積起來;fun3為組合器,將並行處理過程中累積器的各個結果組合起來
然后再看一下有哪些Collector收集器:

Collectors.toList()
Collectors.toSet()
Collectors.toCollection(集合的構造器引用)
Collectors.joining()、Collectors.joining(delimiter)、Collectors.joining(delimiter、prefix、suffix)
字符串元素連接
Collectors.summarizingInt/Long/Double(ToInt/Long/DoubleFunction)
產生Int/Long/DoubleSummaryStatistics對象,它有getCount、getSum、getMax、getMin方法,注意在沒有元素時,getMax和getMin返回Integer/Long/Double.MAX/MIN_VALUE
Collectors.toMap(fun1, fun2)/toConcurrentMap
兩個fun用來產生鍵和值,若值為元素本身,則fun2為Function.identity()
Collectors.toMap(fun1, fun2, fun3)/toConcurrentMap
fun3用於解決鍵沖突,例如(oldValue, newValue) -> oldValue,有沖突時保留原值
Collectors.toMap(fun1, fun2, fun3, fun4)/toConcurrentMap
默認返回HashMap或ConcurrentHashMap,fun4可以指定返回的Map類型,為對應的構造器引元
Collectors.groupingBy(fun)/groupingByConcurrent(fun)
fun是分類函數,生成Map,鍵是fun函數結果,值是具有相同fun函數結果元素的列表
Collectors.partitioningBy(fun)
鍵是true/false,當fun是斷言函數時用此方法,比groupingBy(fun)更高效
Collectors.groupingBy(fun1, fun2)
fun2為下游收集器,可以將列表轉換成其他形式,例如toSet()、counting()、summingInt/Long/Double(fun)、maxBy(Comparator)、minBy(Comparator)、mapping(fun1, fun2)(fun1為轉換函數,fun2為下游收集器)
最后提一下基本類型流,與對象流的不同點如下:

IntStream和LongStream有range(start, end)和rangeClosed(start, end)方法,可以生成步長為1的整數范圍,前者不包括end,后者包括end
toArray方法將返回基本類型數組
具有sum、average、max、min方法
summaryStatics()方法會產生類型為Int/Long/DoubleSummaryStatistics的對象
可以使用Random類的ints、longs、doubles方法產生隨機數構成的流
對象流轉換為基本類型流:mapToInt()、mapToLong()、mapToDouble()
基本類型流轉換為對象流:boxed()
---------------------
作者:Francis長風
來源:CSDN
原文:https://blog.csdn.net/lixiaobuaa/article/details/81099838
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM