當前位置:
首頁 > 知識 > 簡潔的Java8-java8新特性詳解 編程語言

簡潔的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表達式(可以理解為SupplierFunction這些的@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由數據源生成, 經由中間操作串聯起來的一條流水線的轉換, 最後由終端操作觸發執行拿到結果.

簡潔的Java8-java8新特性詳解 編程語言


  1. Source - 對應Stream的生成: -> 如何生成一個Stream;

  2. Transforming - 對應Stream的轉換: -> 如前面的map()filter()limit(), 將原Stream轉換為另一形態;

  3. Operations - 對應Stream的執行: -> 他會真正引發前面一系列Transforming的執行, 並生成一個結果(如ListArrayOptional), 或一個side effect.

我們分別來介紹這些Stream的構成部分:



數據源-Stream生成

除了前面介紹過的collection.stream(), 流的生成方式多種多樣, 可簡單概括為3類: 通用流數值流其他, 其中以通用流最為常用, 數值流是Java為intlongdouble三種數值類型防拆裝箱成本所做的優化:



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 s) Returns an infinite sequential unordered stream where each element is generated by the provided Supplier.
Stream.iterate(T seed, UnaryOperator f) 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 spliterator, boolean parallel) 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 f)
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 mapper)

3. 通用流轉數值流: stream.flatMapToInt(Function mapper)stream.mapToDouble(ToDoubleFunction 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 strs = Arrays.asList("hello", "alibaba", "world");

如何列出裡面各不相同的字元呢?

首先我們想到的是String包含一個split()方法, 將字元串分解為子串, 於是我們這樣寫:

Stream> streamStream = strs.stream() .map(str -> Arrays.stream(str.split("")));1212

我們將String分解成String[]後再由Arrays.stream()String[]映射成Stream, 但這個結果是我們不想看到的: 我們明明想要的是Stream卻得到的是Stream>
, 他把我們想要的結果包到Stream裡面了. 這時候就需要我們的flatMap()
出場了:

Stream stringStream = strs.stream() .flatMap(str -> Arrays.stream(str.split("")));1212

flatMap()Stream中的層級結構扁平化了, 將內層Stream內的元素抽取出來, 最終新的Stream就沒有內層Stream了.


可以簡單概括為: flatMap()方法讓你把一個流中的每個值都換成另一個Stream, 然後把所有的Stream連接起來成為一個Stream.


終端操作-Stream執行

終端操作不僅擔負著觸發流水線執行的任務, 他還需要拿到流水線執行的結果, 其結果為任何不是流的值, 如ListArraybooleanOptional, 甚至是void(forEach()):


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 accumulator) 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 iterator() Returns an iterator for the elements of this stream.
Spliterator 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 警告:深度學習需要新編程語言