Java Stream:第2部分,计数始终是计数吗?
在上一篇有關該主題的文章中 ,我們了解到JDK 8
stream()::count需要更長的時間來執行Stream更多的元素。 對于較新的JDK(例如Java 11),簡單流管道不再是這種情況。 了解JDK本身如何進行改進。
Java 8
在上一篇文章中,我們可以得出結論:
list.stream().count()在Java 8下為O(N) ,即執行時間取決于原始列表中的元素數。 閱讀文章
在這里 。
Java 9及更高版本
正如Nikolai Parlog(@nipafx)和Brian Goetz(@BrianGoetz)在Twitter上正確指出的那樣 ,從Java 9開始改進了Stream::count的實現。下面是對底層代碼的比較
Java 8和更高Java版本之間的Stream::count代碼:
Java 8(來自ReferencePipeline類)
return mapToLong(e -> 1L).sum();Java 9及更高版本(來自ReduceOps類)
if (StreamOpFlag.SIZED.isKnown(flags)) { return spliterator.getExactSizeIfKnown(); } ...對于Java 9和更高版本的分離器,在Java 9和更高版本中似乎出現Stream::count為O(1) ,而不是O(N) 。 讓我們驗證該假設。
基準測試
通過在Java 8和Java 11下運行以下JMH基準可以觀察到big-O屬性:
@State (Scope.Benchmark) public class CountBenchmark { private List<Integer> list; @Param ({ "1" , "1000" , "1000000" }) private int size; @Setup public void setup() { list = IntStream.range( 0 , size) .boxed() .collect(toList()); } @Benchmark public long listSize() { return list.size(); } @Benchmark public long listStreamCount() { return list.stream().count(); } public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() .include(CountBenchmark. class .getSimpleName()) .mode(Mode.Throughput) .threads(Threads.MAX) .forks( 1 ) .warmupIterations( 5 ) .measurementIterations( 5 ) .build(); new Runner(opt).run(); } }這將在我的筆記本電腦(MacBook Pro 2015年中,2.2 GHz Intel Core i7)上產生以下輸出:
JDK 8(來自上一篇文章)
Benchmark (size) Mode Cnt Score Error Units CountBenchmark.listSize 1 thrpt 5 966658591.905 ± 175787129.100 ops/s CountBenchmark.listSize 1000 thrpt 5 862173760.015 ± 293958267.033 ops/s CountBenchmark.listSize 1000000 thrpt 5 879607621.737 ± 107212069.065 ops/s CountBenchmark.listStreamCount 1 thrpt 5 39570790.720 ± 3590270.059 ops/s CountBenchmark.listStreamCount 1000 thrpt 5 30383397.354 ± 10194137.917 ops/s CountBenchmark.listStreamCount 1000000 thrpt 5 398.959 ± 170.737 ops/sJDK 11
Benchmark (size) Mode Cnt Score Error Units CountBenchmark.listSize 1 thrpt 5 898916944.365 ± 235047181.830 ops/s CountBenchmark.listSize 1000 thrpt 5 865080967.750 ± 203793349.257 ops/s CountBenchmark.listSize 1000000 thrpt 5 935820818.641 ± 95756219.869 ops/s CountBenchmark.listStreamCount 1 thrpt 5 95660206.302 ± 27337762.894 ops/s CountBenchmark.listStreamCount 1000 thrpt 5 78899026.467 ± 26299885.209 ops/s CountBenchmark.listStreamCount 1000000 thrpt 5 83223688.534 ± 16119403.504 ops/s 可以看出,在Java 11中, list.stream().count()操作現在是
O(1)而不是O(N) 。
Brian Goetz 指出 ,一些在Java 8下使用Stream::peek方法調用的開發人員發現,如果Stream::count終端操作在Java 9及更高版本下運行,則不再調用這些方法。 這給JDK開發人員帶來了一些負面反饋。 就我個人而言,我認為這是JDK開發人員的正確決定,相反,這為
Stream::peek用戶使他們的代碼正確。
更復雜的流管道
在本章中,我們將介紹更復雜的流管道。
JDK 11
Tagir Valeev 得出結論 ,對于List::stream ,類似stream().skip(1).count()類的管道不是O(1) 。
通過運行以下基準可以觀察到這一點:
因此, list.stream().skip(1).count()仍為O(N)。
加速
一些流實現實際上知道它們的源,并且可以采用適當的快捷方式并將流操作合并到流源本身中。 這可以大大提高性能,尤其是對于具有更復雜的流管道(例如stream().skip(1).count()大型流stream().skip(1).count()
Speedment ORM工具允許將數據庫視為Stream對象,并且這些流可以優化許多流操作,例如
Stream::count , Stream::skip , Stream::limit操作,如下面的基準所示。 我已使用開源Sakila示例數據庫作為數據輸入。 Sakila數據庫包含有關租賃電影,藝術家等的全部信息。
運行時,將產生以下輸出:
SpeedmentCountBenchmark.filmsSkipCount N/A thrpt 5 68052838.621 ± 739171.008 ops/s SpeedmentCountBenchmark.rentalsSkipCount N/A thrpt 5 68224985.736 ± 2683811.510 ops/s“租賃”表包含10,000行,而“電影”表僅包含1,000行。 但是,它們的stream().skip(1).count()操作幾乎同時完成。 即使一個表包含一萬億行,它仍然會在相同的經過時間內對元素進行計數。 因此, stream().skip(1).count()實現的復雜度為O(1)而不是O(N) 。
注意:上面的基準測試是通過“ DataStore” JVM中的內存加速來運行的。 如果直接對數據庫沒有加速運行,則響應時間將取決于基礎數據庫執行嵌套“SELECT count(*) …”語句的能力。
摘要
在Java 9中Stream::count顯著改善。
有些流實現(例如Speedment O(1)即使在更復雜的流管道(例如stream().skip(...).count()甚至stream.filter(...).skip(...).count() stream().skip(...).count() ,也可以在O(1)時間內計算Stream::count stream().skip(...).count() stream.filter(...).skip(...).count() 。
資源資源
Speedment Stream ORM初始化程序: https ://www.speedment.com/initializer/
Sakila: https ://dev.mysql.com/doc/index-other.html或https://hub.docker.com/r/restsql/mysql-sakila
翻譯自: https://www.javacodegeeks.com/2019/04/java-stream-part-2-count-always-count.html
總結
以上是生活随笔為你收集整理的Java Stream:第2部分,计数始终是计数吗?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国王游戏的具体玩法?举些例子最好~
- 下一篇: 如何以及为什么使用Spoon分析,生成和