一点杂感 以及 java8 Streams API 与 C# Linq 简要对比分析
寫在前面的一點小吐槽、一點雜感
學 Haskell 學了一段時間之后,雖說拿他來寫東西還是完全不行,但是看別的語言特性時,總是會帶著一種“誒,這玩意在哪哪見過”的蜜汁既視感。且不說幾乎成為現代編程語言標配的 Lambda 、閉包,就是 Monad 都有不少引入了。
這段時間,出于學校項目需要,又在學習 java 。不知為什么,感覺看起 java 來真的是格外的蛋疼,覺得這玩意語法和某些特性的設計簡直是糟糕,整潔度和美感還不如復雜和妥協的 C++,更別說以語法優雅著稱的 C#。
雖說自己水平渣,但是這樣一門滿是歷史局限性與不優雅的語言,網上不少 java 程序員倒是對這個飽受詬病的語法、api本身一股迷之優越感,完全不知道到底是不知道還是僅僅不想承認 —— java高占有的關鍵 —— 設計思想符合當時的時代進程、社區化的成功、當下的路徑依賴。
到了什么程度呢?大名鼎鼎的《java core》作者,在書中都對其他的語言有一些優勢(有些甚至 —— 個人認為—— 并非優勢只是設計的不同)就大加贊揚,而對被對比方字里行間飽含嘲諷。而對 java 設計缺陷就不甚明顯的提一下。
幾個例子
一次編寫,到處調試(誤)
混亂的標準庫設計
難用的時間、日期庫
孱弱的以擦除實現的泛型系統
偏執的完全不加入隱式類型聲明
只能傳值、不允許運算符重載(這兩個見仁見智)
Linq(后文將會討論)
不支持拓展方法
沒有部分類,導致的寫 GUI 自動代碼生成蛋疼至極
throws
final – sealed
final – const (說實話你 final 不就是一表層 const 么)
delegate (java core 作者說 java 的 method invoke 比 C#的 delegate 更好,完全不能理解)
沒有原生 tuple,pair
其他語法糖的缺乏(如await\asyc)
當然其它語言也有各自的不足,這里只是提這些來印證前文
語言明明只是工具,是為表述思想服務的。如果說像《java core》作者這樣一門語言的布道者尚可說是懷揣著對自己工作的熱愛,是可以理解的。某些明明是格局有限或者單純跟風的人,只能說是可悲了。
就雜感而起的 java8 Streams API 與 C# Linq 簡要對比分析
起因
前段時間給某位老師寫一個系統,api 路由是 node 實現的,一不做二不休干脆全上 node 了。因為要求數據安全,不敢用 mongodb,遂上 mysql,又因為需求不是很復雜,沒想那么多就直接裸寫 sql 了,寫得簡直了,既丑又容易給注入…… 寫完之后才想起來為啥不用 ORM,看了看,那幾個火的 ORM 庫要不太大,要不文檔太簡陋或者相當于設計了一套自己的sql方言。這時候才懷念起c#的linq,太好用了。
項目暫時告一段落后的現在,因為在學習 java 的、聽說c#、java的相似性高的緣故,想要在java中能找到類似的。就在希望快要轉為失望之時,看到了這篇文章。
LINQ一直是.net程序系統中的一個非常棒的東東. Visual Studio 2008 已經引入了lambda 表達式和monads, 而同一時間Java6版本還在討論要不要去掉泛型數據類型. 這一成果要歸功于荷蘭計算機科學家Erik Meijer, 他已經全停止掉別的項目. - Java的現狀? 即將要發布的Java8和JSR-355,我們還需要LINQ?在過去的十幾年中人們一直在嘗試用LINQ給Java帶來性能的改良。當時,Quaere和Lambdaj似乎在研究一種很有前途的庫(非語言級別). 事實上,StackOverflow上有很多Java的使用者提出的有沒有與LINQ等價的Java做法(到現在依然) : LINQ的Java實現? LINQ的Java工具 Java中有跟LINQ類似的東西么? Java等效LINQ和實體框架是什么? 有趣的是, "LINQ"已經發展到EL 3.0版本了!<br> - 我們真的需要LINQ么? LINQ的高級特性存在重大缺陷, 從我們角度看來, 將會導致 "next big impedance mismatch". LINQ來源于SQL,這不是一件完美的事情. LINQ流行的LINQ-to-Objects,在.NET下是一種很好的查詢方式.Haskell或Scala的成功已表明,真正的函數式編程可以忽略SELECT,WHERE,GROUP BY, 或者HAVING等來進行集合查詢。他們使用"fold", "map", "flatMap", "reduce",來獲得更高的性能.另一方面LINQ用 "skip", "take"使用混合式GROUP BY(不是OFFSET和FETCH). 事實上, 沒有一種函數式查詢方法可以超越那老舊但好用的SQL外部鏈接, 分組設置,或 框架窗口功能. 這些結構僅僅是一個SQL開發人員希望看到的結果的聲明。他們不是自足的功能,這實際上包含在任何給定的情況下被執行的邏輯。此外,窗口功能,可以只用在SELECT和ORDER BY子句,這是一種明顯聲明方式,但是如果你沒有SQL上下文這也是非常奇怪的。具體來說,SELECT子句中的窗口函數采用正確的數據預取影響整個執行計劃和索引的方式。 相反,函數式編程可以在內存中就做到SQL的這些功能。使用SQLesque API 進行集合查詢是用函數式方式狡猾的欺騙 了"傳統"的人。這樣的實現方式是不能將集合數據與SQL表查詢的數據合并在一起的,也不會產生預期的SQL查詢結果。 - 我該如何做? 相當簡單,你如果使用SQL,你就有兩個基本選擇: 自上而下,專注你的Java模型. 使用Hibernate / JPA查詢并且使用Java8 Streams API 轉化Hibernate的查詢結果. 自下而上,專注你的SQL關系模型. 繼續使用JDBC或者jOOQ, 使用Java8 Streams API 轉化的查詢結果. - 不能回頭.擁抱未來! 雖然 .NET "領先" Java了一些,但這并不是LINQ的問題. 這主要是由于引入了lambda表達式并且支持lambdas的很多APIs. LINQ僅僅只是如何構建這樣API的例子. 但我更加興奮的期望Java 8中的 new Streams API, 以及它給Java生態系統帶來的函數式編程. 這是一個由Informatech illustrates寫的很棒的一篇博文:如何將常見的LINQ表達式轉換為Java 8 Streams API表達式. 所以,不能回頭.你可以不用再對.NET開發者眼饞嫉妒. 因為Java 8,我們已經不需要LINQ或者其他API模仿LINQ的"unified querying", 有一個更好的稱呼,像"query target impedance mismatch".我們需要真正的SQL關系型數據庫查詢,我們需要Java 8 Streams API函數式編程查詢內存集合數據. 給力 Java 8! |
上面這篇文章中,對 java8 Streams API 的溢美之詞,剛看到標題,仿佛心中頓時像遇到氧氣的帶火星木條似得——一下子復燃了。
然而真的是這樣嗎?或者說真的可以這樣簡單的等價么
正如文中提到,是的,Linq是起源于對強烈的對改善 sql 在某些方面缺陷的渴望。但是,這并不等于說 Linq 是一種簡單 ORM 或者說是用 Lambda 來進行sql查詢的包裝或者說僅僅是語法糖。
linq-to-object的實現
讓我們從相對“表層”的因素因素談起:該文作者在文中談到了 Linq-to-object 的速度,實際上,Linq-to-object在內核的層面就是使用btree的方式實現的,這就相當程度上決定了其效率,從復雜性上說,僅就這一項就可以說明絕不僅是某些開源 java linq 查詢庫那樣的簡單包裝。
讓我們再談一談深層次:
linq的組成
Linq ,或者說一個完整的 Linq ,是由以下幾個部分組成的:
Lambda 表達式
Query 表達式
拓展方法
表達式樹
匿名類型
我們按條目分析:
正如文中提到,java的新版本也加入了lambda特性。
java沒有query表達式,這意味著不能寫成monad形式,而monad作為函數式的重中之重。可以說讓java引入函數式的舉動徒有其表。關于monad,請點擊該鏈接閱讀
前面說到,java新版本實現了lambda,然而設計者們不知何故的沒有支持標準的iterator和iterable,而是選擇引入了一套streams api,試圖實現c# 使用拓展方法實現的功能;結果是又增加了一套steams模型,iostream表示淚流滿地。這樣一來,其效用也僅僅可以用在設計的這些方面,難以拓展。
沒有表達式樹,限制了無法表達語句結構,也限制了動態編譯函數。
java沒有匿名類型,限制了它借助臨時結構減少計算,更使得難以借此增強表達能力。
總結
streams api 是處于語法落后的 java 在函數式上的一次勇敢嘗試和追趕,然而從結果上看,是比較失敗的。或許是某種情結在作怪,怕得到“抄襲”的罪名。然而,這種結果上的殘次 linq 和缺失相當多部分的函數式,更會阻止自身進步的步伐,不能給使用者帶來的便利,可以說是一種對嘗試初心的背反。
總結
以上是生活随笔為你收集整理的一点杂感 以及 java8 Streams API 与 C# Linq 简要对比分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ABP Framework 5.2 RC
- 下一篇: .NET 6 攻略大全(一)