日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java Stream:第2部分,计数始终是计数吗?

發布時間:2023/12/3 java 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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/s

JDK 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) 。

通過運行以下基準可以觀察到這一點:

@Benchmark public long listStreamSkipCount() { return list.stream().skip( 1 ).count(); } CountBenchmark.listStreamCount 1 thrpt 5 105546649.075 ± 10529832.319 ops/s CountBenchmark.listStreamCount 1000 thrpt 5 81370237.291 ± 15566491.838 ops/s CountBenchmark.listStreamCount 1000000 thrpt 5 75929699.395 ± 14784433.428 ops/s CountBenchmark.listStreamSkipCount 1 thrpt 5 35809816.451 ± 12055461.025 ops/s CountBenchmark.listStreamSkipCount 1000 thrpt 5 3098848.946 ± 339437.339 ops/s CountBenchmark.listStreamSkipCount 1000000 thrpt 5 3646.513 ± 254.442 ops/s

因此, 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數據庫包含有關租賃電影,藝術家等的全部信息。

@Benchmark public long rentalsSkipCount() { return rentals.stream().skip( 1 ).count(); } @Benchmark public long filmsSkipCount() { return films.stream().skip( 1 ).count(); }

運行時,將產生以下輸出:

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部分,计数始终是计数吗?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。