為什么需要Stream
Java 8中的Stream是對集合(Collection)對象功能的增強,專注于對集合對象進行便利、高效的聚合操作,或者大批量數(shù)據(jù)操作。Stream API 使用Java 8的新語法Lambda表達式,極大提高編程效率和代碼可讀性。同時提供串行和并行兩種模式,并行操作可以充分利用現(xiàn)代多核處理器的優(yōu)勢,封裝多核并行編程的復雜性,對程序員編程更友善。Java 8中的流式編程是函數(shù)式語言+多核時代的產(chǎn)物。
Java的并行API演變歷程
- 1.0~1.4中的java.lang.Thread
- 5.0中的java.util.concurrent
- 6.0中Phasers等
- 7.0中的Fork/Join框架
- 8.0中的Lambda
最近看了《七周七語言》一書,覺得Java8的流式編程和Lambda表達式,借鑒了許多其他編程語言的特性,特別是基于JVM上的腳本語言。
流的構成
- Collection和數(shù)組
Collection.stream()
Collection.parallelStream()
Arrays.stream(T array)
Stream.of()
- BufferReader
java.io.BufferedReader.lines()
- 靜態(tài)工廠
java.util.stream.IntStream.range()
java.nio.file.Files.walk()
- 自己構造
java.util.Spliterator
- 其他
Random.ints()
BitSet.stream()
Pattern.splitAsStream(java.lang.CharSequence)
JarFile.stream()
流的操作類型
- Intermediate
類似于shell命令的管道符,后續(xù)可以接多個命令。這類操作是惰性化的(lazy),只是調(diào)用方法,并沒有真正開始流的遍歷。
map(mapToInt,flatMap等)、filter、distinct、sorted、peek、limit、skip、parallel、sequential、unordered
特別注意flatMap的使用
- Terminal
一個流只能進行一次terminal操作,即 流只能被消費一次,terminal操作才會開始真正流的遍歷。因此多次Intermediate操作不會增加時間復雜度。
forEach、forEachOrdered、toArray、reduce、collect、min、max、count、anyMatch、allMatch、noneMatch、findFirst、findAny、iterator
- short-circuiting
對于一個intermediate操作,如果接受的是一個無限大的Stream,但返回一個有限的新Stream。
對于一個terminal操作,如果接受的是一個無限大的Stream,但能在有限的時間內(nèi)計算出結果(side effect)。
當操作一個無限大的流,又希望在有限時間內(nèi)完成操作,則在管道內(nèi)擁有一個short-circuriting操作是必要非充分條件(如allMatch,全都滿足條件??)
anyMatch、allMatch、noneMatch、findFirst、findAny、limit
生成自己的流
- Stream.generate
- Stream.iterate
Stream.iterate(0, n -> n + 3).limit(10).forEach(x -> System.out.print(x + " ");
- IntStream.range()
前開后閉
- IntStream.rangeClosed()
閉區(qū)間
IntStream LongStream DoubleStream
提供基本數(shù)據(jù)類型,防止boxing和unboxing影響性能
用Collectors來進行reduction操作
java.util.stream.Collectors
groupingBy/partitioningBy
partitioningBy是一種特殊的groupingBy,分成2組