功能Java示例 第1部分–从命令式到声明式
函數式編程(FP)的目的是避免重新分配變量,避免可變的數據結構,避免狀態并全程支持函數。 如果將功能性技術應用于日常Java代碼,我們可以從FP中學到什么?
在這個名為“ Functional Java by Example”的系列文章中,我將分8步重構現有的一段代碼,以查看是否可以用Java達到Functional Nirvana 。
我對Haskell或F#等“真正的”功能語言沒有太多經驗,但是我希望在每篇文章中以示例方式演示將這些實踐中的一些應用于每天的Java代碼意味著什么。
希望最后您獲得了一些見識,并且知道可以選擇一些有益于您自己的代碼庫的技術。
這些都是這些部分:
- 第1部分–從命令式到聲明式
- 第2部分–命名事物
- 第3部分–不要使用異常來控制流程
- 第4部分–首選不變性
- 第5部分–將I / O移到外部
- 第6部分–用作參數
- 第7部分–將失敗也視為數據
- 第8部分–更多純函數
我將在每篇文章發表時更新鏈接。 如果您通過內容聯合組織來閱讀本文,請查看我博客上的原始文章。
每次代碼也被推送到這個GitHub項目 。
免責聲明:代碼是用Apache的Groovy中 ,主要是為簡潔,所以我不必鍵入的東西(你知道:打字),其中不要緊的例子。 中學,這門語言只是讓我開心。
為什么要關心函數式編程(FP)?
如果您不是在時髦的實時流數據事件處理框架上執行Haskell,F#或Scala,則最好打包。 這些天,甚至JavaScript的人都在圍繞您的方法旋轉函數-這種語言已經存在了一段時間。
那里有很多文章和視頻,使您相信,如果這些天不跳到功能性潮流上,那您將被舊的OOP束縛束縛住,坦白地說,它們在幾年之內就已經過時了。
好吧,我在這里告訴您這不是完全正確的,但是FP 確實有一些前提,例如可讀性,可測試性和可維護性 ,我們也在我們的(企業)Java代碼中力求實現的值正確嗎?
在閱讀本文時,多年以來,您可能已經對FP是前進還是后退或2017-2018年無進展發表了相同的直率觀點,您只是愿意接受新想法
通過學習FP,您可以提高每種語言的技能。
確定自己是什么,你可以從中學到如何自己編程可以從中受益。
如果您能勝任這項任務,那么讓我們從...開始
現有的一些代碼
關于示例代碼的一句話:為這樣的博客提供人為的示例是非常棘手的:它應該足夠容易吸引廣泛的受眾,應該足夠簡單,無需太多上下文就可以理解,但仍然足夠有趣,可以產生理想的學習效果。
展望未來,本系列的每一期都將在前一期的基礎上進行。 下面是我們將作為起點的代碼。
因此,戴上眼鏡,看看您是否熟悉下面的編碼樣式。
class FeedHandler {Webservice webserviceDocumentDb documentDbvoid handle(List<Doc> changes) {for (int i = 0; i < changes.size(); i++) {def doc = changes[i]if (doc.type == 'important') {try {def resource = webservice.create(doc)doc.apiId = resource.iddoc.status = 'processed'} catch (e) {doc.status = 'failed'doc.error = e.message}documentDb.update(doc)}}} }- 這是某種FeedHandler 。
- 它具有兩個屬性,一些Webservice類和DocumentDb類。
- 有一個handle方法可以對Doc對象列表進行處理。 文件?
嘗試弄清楚這里發生了什么
..
..
..
做完了嗎
讀這樣的東西有時會使您感到自己像一個解析器。
掃描類名稱( FeedHandler? )和一個方法( void handle )可以使您感到有些FeedHandler? ,從而使您感到FeedHandler? 。
但是,弄清楚在handle方法中確切地“處理”了什么要困難得多。
- 那里有一個for-loop -但是到底是在迭代什么? 多少次?
- 調用此變量webservice ,返回稱為resource 。
- 如果webservice成功返回,則正在迭代的doc (文檔?)將更新為狀態。
- 似乎webservice還可以拋出一個Exception ,它被捕獲和文檔與其他狀態更新。
- 最終,該文檔被此documentDb實例“更新”。 看起來像一個數據庫。
- 等等,這僅適用于“重要”文檔 -在執行上述所有操作之前,首先檢查doc.type 。
也許,您聽說過以下短語:
讀取的代碼多于編寫的代碼。
看看這塊美麗:
for (int i = 0; i < changes.size(); i++) {上面的代碼以命令式的方式編寫,這意味著操作狀態和行為的具體語句被明確地寫出。
- 用零初始化一個int i
- 當int i小于changes列表的大小時循環
- 每次迭代以1遞增int i
以這種命令式 (過程)編碼方式(大多數主流語言,包括Java,C ++,C#等面向對象編程(OOP)語言,都被設計為主要支持),開發人員編寫了計算機所需的確切語句。執行以完成特定任務。
一些非常命令性 (過程性)代碼的信號:
該代碼明確地集中在“如何”上,這使得“什么”難以確定。
專注于什么
就像本文的標題一樣,我們的第一步是從命令式的編碼和重構方式轉變為更具聲明性的樣式-FP是一種形式。
這個循環最困擾我。
這是代碼的新版本。
class FeedHandler {Webservice webserviceDocumentDb documentDbvoid handle(List<Doc> changes) {// for (int i = 0; i < changes.size(); i++) {// def doc = changes[i]changes.findAll { doc -> doc.type == 'important' }.each { doc ->try {def resource = webservice.create(doc)doc.apiId = resource.iddoc.status = 'processed'} catch (e) {doc.status = 'failed'doc.error = e.message}documentDb.update(doc)}} }有什么變化?
- if (doc.type == 'important')部分已替換為findAll { doc -> doc.type == 'important' } if (doc.type == 'important') findAll { doc -> doc.type == 'important' } findAll { doc -> doc.type == 'important' }再次涉及文檔集合本身- 意思是“查找所有重要的文檔,并僅返回那些重要文檔的新集合”
- 強制性的for-loop (帶有中間的i變量)已由文檔集合本身上的聲明性的each方法所代替- 意思是“為列表中的每個文檔執行一段代碼,我不在乎您如何執行” &#55357;&#56898;
不用擔心each和findAll :這些方法是Groovy所添加的,我將它們與Java在同一代碼庫中愉快地一起使用,添加到任何Collection中,例如Set,List,Map。 Vanilla Java 8具有等效的機制,例如forEach可以更聲明性地迭代集合。
導致可讀軟件的原因是:
描述“什么”而不是“如何” 。
如果我以更具功能性的風格編寫代碼,就可以輕松地看到發生了什么,這可以節省我的時間 (因為是的,我90%的時間都在讀取代碼而不是編寫代碼),并且這樣編寫代碼不容易出錯 ,因為更少的行會減少隱藏錯誤的機會。
現在就這樣
在第2部分中,我們將正確命名事物 ,為更多功能的編程鋪平道路,例如在本系列的后續版本中,“ Either”或“ Try”。
翻譯自: https://www.javacodegeeks.com/2017/11/functional-java-example-part-1-imperative-declarative.html
總結
以上是生活随笔為你收集整理的功能Java示例 第1部分–从命令式到声明式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pc游戏安卓移植版(pc游戏安卓)
- 下一篇: 肥东县房产局网上备案查询(肥东县房产局网