带有谓词的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.mzph.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;是非常先进的工具…