簡潔的Java8-java8新特性詳解 編程語言
Stream
標籤 : Java基礎
再次回到阿里, 感覺變化好大: 一是服務資源Docker化, 最牛逼的阿里DB團隊竟然把DB放到了容器中, 還放到了線上環境; 二是全集團Java8(記得離開時還是1.6、1.5, 甚至還有1.4), 在外面創業公司都還停留在1.7的時代, 阿里竟率先使用了Java8, 而且還做了高性能的定製, 因此阿里人也就有機會在生產環境體驗到Java8如絲般的順滑流暢. 而本篇就從對Java8影響最大的
Stream
開始說起.
引入
如果說
Runnable
介面是將執行邏輯從Thread
中剝離了的話, 那Stream
則是將數據計算邏輯從Collection
中抽離了出來, 使Collection
只專註於數據的存儲, 而不用分心計算.
打開Collection
Api可以看到多了一個stream()
default
介面:
/**
Stream
允許以聲明方式處理集合等可以轉換為Stream
的數據, 他有很多特點:
內部迭代
與原有的Iterator不同, Stream將迭代操作(類似for/for-each
)全部固化到了Api內部實現, 用戶只需傳入表達計算邏輯的lambda表達式(可以理解為Supplier、Function這些的@FunctionalInterface的實現),
Stream
便會自動迭代數據觸發計算邏輯並生成結果. 內部迭代主要解決了兩方面的問題: 避免集合處理時的套路和晦澀; 便於庫內部實現的多核並行優化.
流水線
很多Stream操作會再返回一個Stream
, 這樣多個操作就可以鏈接起來, 形成一個大的流水線, 使其看起來像是對數據源進行資料庫式查詢, 這也就讓自動優化成為可能, 如隱式並行.
隱式並行 如將
.stream()替換為.parallelStream(),Stream
則會自動啟用Fork/Join框架, 並行執行各條流水線, 並最終自動將結果進行合并.
延遲計算
由於Stream大部分的操作(如filter()、generate()、map()
…)都是接受一段lambda表達式, 邏輯類似介面實現(可以看成是回調), 因此代碼並不是立即執行的, 除非流水線上觸發一個終端操作, 否則中間操作不會執行任何處理.
短路求值
有些操作不需要處理整個流就能夠拿到結果, 很多像anyMatch()、allMatch()、limit()
, 只要找到一個元素他們的工作就可以結束, 也就沒有必要執行後面的操作, 因此如果後面有大量耗時的操作, 此舉可大大節省性能.
下面一個示例直觀的感受下Stream
帶來的便利:
public void joiningList() { // 生成一段[0,20)序列
Stream 構成
一個流管道(Stream pipeline)通常由3部分構成: 數據源(Source) -> 中間操作/轉換(Transforming) -> 終端操作/執行(Operations): Stream
由數據源生成, 經由中間操作串聯起來的一條流水線的轉換, 最後由終端操作觸發執行拿到結果.
Source - 對應Stream的生成: -> 如何生成一個Stream;
Transforming - 對應Stream的轉換: -> 如前面的
map()
、filter()
、limit()
, 將原Stream
轉換為另一形態;Operations - 對應Stream的執行: -> 他會真正引發前面一系列Transforming的執行, 並生成一個結果(如
List
、Array
、Optional
), 或一個side effect.
我們分別來介紹這些Stream的構成部分:
數據源-Stream生成
除了前面介紹過的collection.stream()
, 流的生成方式多種多樣, 可簡單概括為3類: 通用流、數值流、其他, 其中以通用流最為常用, 數值流是Java為int、long、double
三種數值類型防拆裝箱成本所做的優化:
1. 通用流
API | description |
---|---|
Arrays.stream(T[] array) | Returns a sequential Stream with the specified array as its source. |
Stream.empty() | Returns an empty sequential Stream. |
Stream.generate(Supplier |
Returns an infinite sequential unordered stream where each element is generated by the provided Supplier |
Stream.iterate(T seed, UnaryOperator |
Returns an infinite sequential ordered Stream produced by iterative application of a function f to an initial element seed, producing a Stream consisting of seed, f(seed), f(f(seed)), etc. |
Stream.of(T... values) | Returns a sequential ordered stream whose elements are the specified values. |
Stream.concat(Stream a, Stream b) | Creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream. |
StreamSupport.stream(Spliterator |
Creates a new sequential or parallel Stream from a Spliterator. |
2. 數值流
API | description |
---|---|
Arrays.stream(Xxx[] array) | Returns a sequential Int/Long/DoubleStream with the specified array as its source. |
XxxStream.empty() | Returns an empty sequential Int/Long/DoubleStream. |
XxxStream.generate(XxxSupplier s) | Returns an infinite sequential unordered stream where each element is generated by the provided Int/Long/DoubleSupplier. |
XxxStream.iterate(Xxx seed, XxxUnaryOperator f) | Returns an infinite sequential ordered Int/Long/DoubleStreamlike as Stream.iterate(T seed, UnaryOperator |
XxxStream.of(Xxx... values) | Returns a sequential ordered stream whose elements are the specified values. |
XxxStream.concat(XxxStream a, XxxStream b) | Creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream. |
Int/LongStream.range(startInclusive, endExclusive) | Returns a sequential ordered Int/LongStream from startInclusive (inclusive) to endExclusive (exclusive) by an incremental step of 1. |
Int/LongStream.rangeClosed(startInclusive, endInclusive) | Returns a sequential ordered Int/LongStream from startInclusive (inclusive) to endInclusive (inclusive) by an incremental step of 1. |
3. 其他
I/O Stream
BufferedReader.lines()
File Stream
Files.lines(Path path)
Files.find(Path start, int maxDepth, BiPredicate
matcher, FileVisitOption... options) DirectoryStream
newDirectoryStream(Path dir) Files.walk(Path start, FileVisitOption... options)
Jar
JarFile.stream()
Random
Random.ints()
Random.longs()
Random.doubles()
Pattern
splitAsStream(CharSequence input)
…
另外, 三種數值流之間, 以及數值流與通用流之間都可以相互轉換:
1. 數值流轉換:
doubleStream.mapToInt(DoubleToIntFunction mapper)
、intStream.asLongStream()
…2. 數值流轉通用流:
longStream.boxed()
、intStream.mapToObj(IntFunction extends U> mapper)
…3. 通用流轉數值流:
stream.flatMapToInt(Function super T,? extends IntStream> mapper)
、stream.mapToDouble(ToDoubleFunction super T> mapper)
…
中間操作-Stream轉換
所有的中間操作都會返回另一個Stream
, 這讓多個操作可以鏈接起來組成中間操作鏈, 從而形成一條流水線, 因此它的特點就是前面提到的延遲執行: 觸發流水線上觸發一個終端操作, 否則中間操作不執行任何處理.
API | Description |
---|---|
filter(Predicate predicate) | Returns a stream consisting of the elements of this stream that match the given predicate. |
distinct() | Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream. |
limit(long maxSize) | Returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length. |
skip(long n) | Returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream. |
sorted(Comparator comparator) | Returns a stream consisting of the elements of this stream, sorted according to the provided Comparator. |
map(Function mapper) | Returns a stream consisting of the results of applying the given function to the elements of this stream. |
flatMap(Function> mapper) | Returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. |
peek(Consumer action) | Returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream. |
這裡著重講解下flatMap()
, 因為我在第一次接觸他時也沒明白他到底能做什麼: 假設我們有這樣一個字元串list:List
如何列出裡面各不相同的字元呢?
首先我們想到的是String包含一個split()
方法, 將字元串分解為子串, 於是我們這樣寫:
Stream 我們將String分解成String[]後再由Arrays.stream()將String[]映射成Stream Stream 可以簡單概括為: 終端操作-Stream執行 終端操作不僅擔負著觸發流水線執行的任務, 他還需要拿到流水線執行的結果, 其結果為任何不是流的值, 如
, 他把我們想要的結果包到Stream裡面了. 這時候就需要我們的flatMap()
出場了:flatMap()
把Stream
中的層級結構扁平化了, 將內層Stream
內的元素抽取出來, 最終新的Stream
就沒有內層Stream
了.
flatMap()
方法讓你把一個流中的每個值都換成另一個Stream
, 然後把所有的Stream
連接起來成為一個Stream
.List、Array、boolean、Optional
Api
Description
count()
Returns the count of elements in this stream.
max(Comparator comparator)
Returns the maximum element of this stream according to the provided Comparator.
min(Comparator comparator)
Returns the minimum element of this stream according to the provided Comparator.
allMatch(Predicate predicate)
Returns whether all elements of this stream match the provided predicate.
anyMatch(Predicate predicate)
Returns whether any elements of this stream match the provided predicate.
noneMatch(Predicate predicate)
Returns whether no elements of this stream match the provided predicate.
findAny()
Returns an Optional describing some element of the stream, or an empty Optionalif the stream is empty.
findFirst()
Returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty.
reduce(BinaryOperator
Performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any.
toArray()
Returns an array containing the elements of this stream.
forEach(Consumer action)
Performs an action for each element of this stream.
forEachOrdered(Consumer action)
Performs an action for each element of this stream, in the encounter order of the stream if the stream has a defined encounter order.
collect(Collector collector)
Performs a mutable reduction operation on the elements of this stream using a Collector.
像
IntStream
/LongStream
/DoubleStream
還提供了average()
、sum()
、summaryStatistics()
這樣的操作, 拿到一個對Stream
進行匯總了的結果.
other
java.util.stream.Stream
介面集成自java.util.stream.BaseStream
介面, 而BaseStream
介面也提供了很多工具方法(如將串列流轉換為並行流的parallel()
方法)供我們使用:
Api | Description |
---|---|
S onClose(Runnable closeHandler) | Returns an equivalent stream with an additional close handler. |
void close() | Closes this stream, causing all close handlers for this stream pipeline to be called. |
S unordered() | Returns an equivalent stream that is unordered. |
Iterator |
Returns an iterator for the elements of this stream. |
Spliterator |
Returns a spliterator for the elements of this stream. |
S sequential() | Returns an equivalent stream that is sequential. |
S parallel() | Returns an equivalent stream that is parallel. |
boolean isParallel() | Returns whether this stream, if a terminal operation were to be executed, would execute in parallel. |
綜合實戰
下面, 我們針對一系列交易提出一些問題綜合實踐上面列舉的Api:
DO定義
/**
Stream操作
/**
※Linux內核頁面換入換出
※C++實現稀疏矩陣的壓縮存儲
※Linux系統CPU的性能監控及調優
※DLL注入技術
※SQL Server 2017中新的T-SQL函數
TAG:青峰科技 |
※GitHub趨勢榜第二名:解析、對比不同編程語言的Semantic庫
※vscode寫c語言(windows)
※MIT正式發布編程語言Julia 1.0:Python、R、C+三合一
※Rust 逆襲!位列 Stack Overflow 2018 最受歡迎編程語言榜首
※大師語言 | John William Godward
※Adobe Photoshop CC 2018 Win/Mac 中文/英文/多語言破解版
※身體的語言 ya.tender-1
※Julia:集Python、C+、R等語言為一體的全新語言
※Canonical宣布Kotlin編程語言Snap包格式上線
※ios11越獄Electra界面語言改為中文簡體
※PS4/Xbox One/Steam《生化危機0/1 重製版》更新簡繁中文語言包
※微軟基於F 的 Liqui|> 量子編程語言
※為什麼成立中韓語言交流會?The Language Exchange of Dreamtalk in Shanghai
※集 Python、C、R、Ruby 之所長,動態編程語言 Julia 1.0 正式發布
※微軟推最新程序語言Bosque 以Functors取代Loop循環
※Firefox Reality VR瀏覽器支持7種新語言,書籤等
※IEEE Spectrum 2018 年度編程語言排行榜,Python 衛冕
※Facebook新研究:一個編碼器hold住93種語言!跨語言遷移無需修改
※用R語言的Blogdown+Hugo+Netlify+Github建博客
※再見 Python!Yann LeCun 警告:深度學習需要新編程語言