帶有謂詞的Java中的功能樣式-第1部分

您一直在聽到將要席卷全球的函數式編程,而您仍然堅持使用普通Java? 不用擔心,因為您已經可以在日常Java中添加一些功能樣式。 此外,它很有趣,可以節省許多代碼行并減少錯誤。

什么是謂詞?

實際上,當我很早以前在Java 1.4中進行編碼時,我第一次發現Apache Commons Collections時就愛上了謂詞。 該API中的謂詞不過是Java界面,僅包含一種方法:

evaluate(Object object): boolean

就是這樣,它只需要一些對象并返回true或false。 帶有Apache許可證2.0的Google Guava是Apache Commons Collections的更新版本。 它使用通用參數通過一種方法定義了謂詞接口:

apply(T input): boolean

就這么簡單。 要在您的應用程序中使用謂詞,您只需在自己的單個方法apply(something)中使用您自己的邏輯來實現此接口。 ?

一個簡單的例子

作為早期的示例,假設您有一個PurchaseOrder對象的列表訂單 ,每個訂單都有一個日期,一個Customer和一個州。 各種用例可能會要求您找出該客戶的每筆訂單,或者每筆待處理,已發貨或已交付的訂單,或者自上一小時以來完成的每筆訂單。 當然,您可以通過foreach循環和if內部循環來做到這一點:

//List<PurchaseOrder> orders...public List<PurchaseOrder> listOrdersByCustomer(Customer customer) {final List<PurchaseOrder> selection = new ArrayList<PurchaseOrder>();for (PurchaseOrder order : orders) {if (order.getCustomer().equals(customer)) {selection.add(order);}}return selection;
}

再次針對每種情況:

public List<PurchaseOrder> listRecentOrders(Date fromDate) {final List<PurchaseOrder> selection = new ArrayList<PurchaseOrder>();for (PurchaseOrder order : orders) {if (order.getDate().after(fromDate)) {selection.add(order);}}return selection;
}

重復非常明顯:除了if子句中的條件(此處以黑體強調)之外,每個方法都是相同的。 使用謂詞的想法僅是通過對謂詞的調用來替換if子句中的硬編碼條件,該調用隨后成為參數。 這意味著您只能編寫一個方法,以謂詞作為參數,并且仍然可以覆蓋所有用例,甚至已經支持了您尚不知道的用例:

public List<PurchaseOrder> listOrders(Predicate<PurchaseOrder> condition ) {final List<PurchaseOrder> selection = new ArrayList<PurchaseOrder>();for (PurchaseOrder order : orders) {if (condition.apply(order)) {selection.add(order);}}return selection;
}

每個謂詞可以在多個地方定義為獨立類,也可以定義為匿名類:

final Customer customer = new Customer("BruceWaineCorp");
final Predicate<PurchaseOrder> condition = new Predicate<PurchaseOrder>() {public boolean apply(PurchaseOrder order) {return order.getCustomer().equals(customer);}
};

使用真正的函數式編程語言(Scala,Clojure,Haskell等)的朋友會評論說,上面的代碼非常冗長,無法完成某些非常常見的事情,我必須同意。 但是,我們已經習慣了Java語法中的冗長性,并且我們擁有功能強大的工具(自動完成,重構)來適應它。 而且我們的項目可能無法在一夜之間切換到另一種語法。 ?

謂詞是收藏最好的朋友

回到我們的示例,我們只編寫了一次foreach循環來覆蓋每個用例,并且我們對分解出來的內容感到滿意。 但是,您的朋友“真正地”進行函數式編程仍然可以嘲笑您必須自己編寫的循環。 幸運的是,來自Apache或Google的API也都提供了您可能期望的所有優點,特別是類似于java.util.Collections的類,因此命名為Collections2 (不是一個非常原始的名稱)。

此類提供了一個方法filter() ,它的功能類似于我們之前編寫的內容,因此我們現在可以完全不使用循環來重寫方法:

public Collection<PurchaseOrder> selectOrders(Predicate<PurchaseOrder> condition) {return Collections2.filter(orders, condition);
}

實際上,此方法返回一個篩選視圖:

返回的集合是unfiltered的實時視圖(輸入集合); 改變一個會影響另一個。

這也意味著更少的內存使用,因為是從未經過濾的 過濾 ,以實際返回的集合初始收集沒有實際的副本。

在類似的方法上,給定一個迭代器,您可以在它之上請求一個過濾的迭代器(Decorator模式),該迭代器僅為您提供謂詞選擇的元素:

Iterator filteredIterator = Iterators.filter(unfilteredIterator, condition);

由于Java 5的Iterable接口在foreach循環中非常方便使用,因此我們確實希望使用以下表達式:

public Iterable<PurchaseOrder> selectOrders(Predicate<PurchaseOrder> condition) {return Iterables.filter(orders, condition);
}// you can directly use it in a foreach loop, and it reads well:
for (PurchaseOrder order : orders.selectOrders(condition)) {//...
}

現成的謂詞

要使用謂詞,您可以簡單地定義自己的接口謂詞,或者為應用程序中需要的每個類型參數定義一個。 這是可能的,但是使用來自諸如Guava或Commons Collections之類的API的標準謂詞接口的好處是,API帶來了許多出色的構建塊,可與您自己的謂詞實現結合使用。

首先,您甚至根本不需要實現自己的謂詞。 如果您所需要的只是一個對象是否等于另一個條件或不為空的條件,那么您可以簡單地要求謂詞:

// gives you a predicate that checks if an integer is zero
Predicate<Integer> isZero = Predicates.equalTo(0);
// gives a predicate that checks for non null objects
Predicate<String> isNotNull = Predicates.notNull();
// gives a predicate that checks for objects that are instanceof the given Class
Predicate<Object> isString = Predicates.instanceOf(String.class);

給定一個謂詞,您可以將其求逆(true變為false,反之亦然):

Predicates.not(predicate);

使用布爾運算符AND或OR組合多個謂詞:

Predicates.and(predicate1, predicate2);
Predicates.or(predicate1, predicate2);
// gives you a predicate that checks for either zero or null
Predicate<Integer> isNullOrZero = Predicates.or(isZero, Predicates.isNull());

當然,您還有特殊的謂詞,它們總是返回true或false,它們確實非常有用,我們將在以后的測試中看到:

Predicates.alwaysTrue();
Predicates.alwaysFalse();

謂詞在哪里

我通常經常一開始會做匿名謂語,但是它們總是經常被使用,因此經常被提升為實際的類,無論是否嵌套。

順便說一下,這些謂詞在哪里定位? 遵循羅伯特·C·馬丁( Robert C. Martin) 及其共同封閉原則(CCP) :

一起變化的類,一起屬于

因為謂詞操縱某種類型的對象,所以我喜歡將它們共置為靠近它們作為參數的類型。 例如,類CustomerOrderPredicatePendingOrderPredicateRecentOrderPredicate應該與它們評估的PurchaseOrder類駐留在同一包中,或者如果它們很多,則駐留在子包中。 另一種選擇是定義它們嵌套在類型本身內。 顯然,謂詞與它們所操作的對象非常相關。

資源資源

以下是本文示例的源文件: cyriux_predicates_part1 (zip)

在下一部分中 ,我們將了解謂詞如何簡化測試,它們與域驅動設計中的規范之間的關系以及一些其他方面的知識,以使您的謂詞發揮最大作用。

參考: 帶有謂詞的純Java語言中的功能樣式 -Cyrille Martraire博客博客中來自JCG合作伙伴 Cyrille Martraire的第1部分 。


翻譯自: https://www.javacodegeeks.com/2012/05/functional-style-in-java-with.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372789.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372789.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372789.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

寶塔添加多占點_寶塔面板啟用WordPress多站點子域名、子目錄

其實在很早以前&#xff0c;陌小雨就聽說了 wordpress 的多站點功能&#xff0c;不過因為不清楚&#xff0c;所以懶得折騰&#xff0c;這不這幾天閑著蛋疼&#xff0c;好好研究了下這玩意&#xff0c;用起來的感覺還是相當不錯的&#xff0c;總結起來就是如果你準備開始用 word…

centos 6.5下安裝文件上傳下載服務

centos 6.5下安裝文件上傳下載服務 由于每次在CentOS中要下載一些配置文件到物理機&#xff0c;和上傳一些文件到服務器&#xff0c;導致來回的開啟ftp軟件有點麻煩&#xff0c;這里我們可以使用文件上傳下載服務&#xff0c;來解決上傳和下載的問題。 1.登錄服務器 2.執行命令…

Jenkins 入門系列--jenkins 介紹

第一章 Jenkins是什么&#xff1f; Jenkins 是一個可擴展的持續集成引擎。 主要用于&#xff1a; l 持續、自動地構建/測試軟件項目。 l 監控一些定時執行的任務。Jenkins擁有的特性包括&#xff1a; l 易于安裝-只要把jenkins.war部署到servlet容器&#xff0c;不需要數據庫支…

在方法參數上使用final關鍵字

經過一些自己的混淆&#xff0c;最終博客方法的具體含義&#xff08;最終聲明的方法參數&#xff09;將對此博客條目進行澄清。 至少可以將方法參數上的final關鍵字視為Java編譯器的指示符&#xff0c;表明該參數不能重新分配給另一個引用。 Java參數處理始終是“按值調用” &a…

PHP MySQLi 增刪改查

最近幾天&#xff0c;我們一直在學習利用MySQLi訪問數據庫并對其中的數據進行操作。今天給大家展現一個完整的例子&#xff0c;我們來制作一個新聞發布系統&#xff0c;利用MySQLi來操作數據庫&#xff0c;實現對新聞的添加、修改、刪除、查詢等基本功能。&#xff08;以下代碼…

20162303《程序設計與數據結構》第一周學習總結

學號 2016-2017-2 《程序設計與數據結構》第1周學習總結 教材學習內容總結 本周學習了基本的JAVA知識&#xff0c;雖然比較基礎&#xff0c;但是在實際過程中還是出現了許許多多的問題&#xff0c;代碼一遍遍的敲錯&#xff0c;又一遍遍的修改&#xff0c;剛開始甚至不會切換模…

Java EE與NoSQL的未來

自一段時間以來&#xff0c;我一直在關注NoSQL的近期發展勢頭&#xff0c;似乎這個流行語也引起了企業Java界的某種關注。 即EclipseLink 2.4開始支持MongoDB和Oracle NoSQL 。 將EclipseLink作為JPA參考實現&#xff0c;您可能想知道這對Java EE 7意味著什么。這里簡短說明&am…

【C/C++開發】C語言實現函數可變參數

函數原型: int printf(const char *format[,argument]...) 返 回 值: 成功則返回實際輸出的字符數&#xff0c;失敗返回-1. 函數說明: 在printf()函數中&#xff0c;format后面的參數個數不確定&#xff0c;且類型也不確定&#xff0c;這些參數都存放在棧內.調用…

java postgresql json_java – 將PostgreSQL JSON列映射到Hibernate值類...

See PgJDBC bug #265.PostgreSQL對數據類型轉換過于嚴格,非常嚴格.它不會隱式地將文本轉換為類似文本的值,例如xml和json.解決此問題的嚴格正確方法是編寫使用JDBC setObject方法的自定義Hibernate映射類型.這可能有點麻煩,所以你可能只想通過創建一個較弱的強制轉換來使Postgr…

面向接口編程詳解(三)——模式研究

通過前面兩篇&#xff0c;我想各位朋友對“面向接口編程”的思想有了一定認識&#xff0c;并通過第二篇的例子&#xff0c;獲得了一定的直觀印象。但是&#xff0c;第二篇中的例子旨在展示面向接口編程的實現方法&#xff0c;比較簡單&#xff0c;不能體現出面向接口編程的優勢…

錯誤學習:Java + OSGi

最近&#xff0c;我致力于在OSGi環境中使Apache Hive工作。 雖然沒有被證明是小菜一碟&#xff08;軟件對嗎&#xff1f;。。為什么我不感到驚訝&#xff1f; &#xff09;&#xff0c;它引導我解決了各種Java和OSGi錯誤。 在這里&#xff0c;我列出了其中一些讓我有些吃力的東…

iOS多Targets管理

序言&#xff1a; 個人不善于寫東西&#xff0c;就直奔主題了。 其實今天會注意到多targets這個東西&#xff0c;是因為在學習一個第三方庫FBMemoryProfiler的時候&#xff0c;用到了&#xff0c;所以就搜索了一些相關資料&#xff0c;就在這里記錄一下。 可能每個人都會遇到這…

優化的34條定律

1.Minimize HTTP Requests 減少HTTP請求 圖片、css、script、flash等等這些都會增加http請求數&#xff0c;減少這些元素的數量就能減少響應時間。把多個JS、CSS在可能的情況下寫進一個文件&#xff0c;頁面里直接寫入圖片也是不好的做法&#xff0c;應該寫進CSS里&#xff0c;…

休眠提示:排序和排序

讓我們介紹另一個休眠性能提示。 你還記得以前的休眠的模式后 &#xff1f; 我們有一個與一對多協會有關的星際飛船和軍官。 Entity public class Starship {Id GeneratedValue(strategyGenerationType.SEQUENCE) private Long id;public Long getId() {return id;}protected v…

java 基本類型 線程安全_java的基本類型和i++線程安全性的深入解析

在java中&#xff0c;除了long和double的8個字節、64位比特的變量外&#xff0c;其他的基本變量都是原子性的。java存儲模型要求獲取和存儲操作都為原子性&#xff0c;但是對于非volatile的long和double變量&#xff0c;jvm允許將64位的讀或寫劃分為兩個32位的操作。如果讀和寫…

MySQL配置文件mysql.ini參數詳解

my.ini&#xff08;Linux系統下是my.cnf&#xff09;&#xff0c;當mysql服務器啟動時它會讀取這個文件&#xff0c;設置相關的運行環境參數。 my.ini分為兩塊&#xff1a;Client Section和Server Section。 Client Section用來配置MySQL客戶端參數。 要查看配置參數可以用下面…

微信公眾平臺和微信開放平臺的區別

自己也剛開始做微信開發&#xff0c;先寫寫自己的認識&#xff1a; 用微信公眾平臺可以做手機端H5頁面的微信登錄&#xff0c;微信支付 用微信開放平臺可以做PC端網頁的微信登錄。 轉載于:https://www.cnblogs.com/mafeng/p/5610770.html

java 傳遞bean_如何將bean作為參數傳遞給JSP標記?

我ve created a custom JSP tag that is supposed to accept a list of products to render, but I我無法弄清楚如何將列表傳遞給標簽 . 產品列表作為頁面范圍的bean存在 . Web應用程序使用Struts taglib在Struts 1.2.x中編寫 .這是我的代碼的簡化版本&#xff1a;renderProduc…

Business Component(BC)和Business Object(BO)

Siebel應用架構的一個成功的地方就是在應用里引入了BC&#xff0c;BO的概念&#xff0c;從而使得幾千張關系數據表能夠按照業務的含義組織成業務對象&#xff0c;對于業務人員而言具有了業務上的含義&#xff0c;而不僅僅是從技術人員的觀點來對待數據&#xff08;就是關系表而…

NetBeans可用性提示

的Java IDE都來了&#xff0c;因為在很長的路要走天的JBuilder的 &#xff08;盡管JBuilder中似乎是一個值得歡迎提前在時間&#xff09;。 當今的Java IDE&#xff08;例如NetBeans &#xff0c; Eclipse &#xff0c; IntelliJ IDEA和JDeveloper &#xff09;是非常先進的工具…