真是不錯的問答,有原工作人員出來說明來龍去脈才能了解為什麼 Java 多了另一個很像 Iterable 的 Stream。
一切都是舊時代的包袱啊
自從去年轉到 Java8 之後,我的程式到處都充滿了 Stream,我看其他的 Java8 使用者也是如此,根本就回不去 for loop 了。我想三、四年後大部份的 Java 開發者會逐漸接受 functional programming style。
Stream 只能用一次,有什麼問題嗎?在實務上,我有幾次會想要重用 Stream,但無奈不支援,所以把它 collect()
成 List
再使用 (通常在 DAO 裡)。但是這樣的例子實在是不多,而且很簡單就能解決。看了這個問答才讓我了解到原來為了避開 讓開發者 surprise ,Stream 才脫離 Iterable,長成現在這個樣子。
另一件事就是使用 Stream 時實務上容易有 Bug 嗎 ? 現在要我想起來運用 Stream 時有產生什麼 bug 我還真的想不起來,即使已經寫了一年了。bug rate 很低啊這。用起來就是物件在中間一直轉轉轉的,很順手。這種 隱性 的功能完全是靠設計者們的功力和心力了。
Stream 到底有沒有難用,容易有 bug 的地方?還是有啦,就是使用 Parrelell Stream 時充滿了驚奇 (壞的意味),Parrelell 真是難駕馭的怪獸,結果通常不是自己想要的 (包含運算結果和效能...),我現在只能在 unit test 時用一用。還好平行運算不是日常開發會遇到的工作,這個缺點還不算太嚴重。
從實戰的角度來看,Java 8 Stream 的設計人做了一些妥協,而這個妥協滿足了大部份的需求 (就我來看是 95:5 的比例,只有 5 % 會想要重用 Stream),Bug 也少,這算是很成功的設計。當然啦,如果 Java 第一天就俱備 lazy evaluation functional programming 概念,我們會看到更完美的設計,就像 Dart 一樣,而不是現在 Collection
、Iterable
、Iterator
、Stream
等類似的概念在衝突。
做成 one-off 比較好啊,在 Scala Stream 是 lazy memorization collection ,我們最近一個月就踩到了兩次問題,造成 OutOfMemoryError
val stream = (1 to 10000).toStream
.map(id => dao.find(id)) // 1
.flatMap(_.getOptionalInt) // 2
.filter(_ < 10) // 3
.foldLeft(0)((ret, a) => ret + a)
這看起來是把一萬個 object ,取出其中的一個 Int 參數,過濾掉小於 10 的數值,再一個個取出來相加,並不會造成太大的的計憶體負擔,但實際上卻生成了 1, 2, 3 個各有一萬個 object 的 Stream
一不小心,就丟 OutOfMemoryError 了
對我來說最大的問題就是看java doc還是不會用xd 要用背的或剪貼code。很難想像之後scjp納入stream以後考題會長怎樣
是指 collect 的後半那一段吧? 那的確很難。不過我覺得那個跟學 SQL 時的感覺很像,你就是大概知道怎麼用,不過複雜一點的就要試幾次才會對,而且很多時候都要找範例來看。