lambda 加和_流畅和稳定的API的Lambda

lambda 加和

几周前,我写了关于Java 8 lambda的介绍 。 在本简介中,我解释了什么是lambda以及如何将它们与Java 8中也引入的新Stream API结合使用。

Stream API为集合提供了更实用的接口。 此接口在很大程度上取决于lambda。 但是,lambda不仅具有改进的收集处理能力,还具有更多优势

Lambda为您提供了构建更流畅的API的机会。 为了说明这一点,作为示例,我喜欢使用UserStore ,它有助于使用数据库获取和保存用户。 它的公共API通常如下所示。

public interface UserStore {User find(Long id);List<User> findByLastname(String lastname);List<User> findByCompany(String company);..
}

findBy方法的列表通常比我在此处包括的两个方法更长。 随着系统的发展,可能还会有其他人。 尽管可行,但实际上所有这些方法都可以完成相同的事情。 他们返回具有匹配特定值的属性的所有用户。

一些框架提供了解决此问题的方法。 如果您使用过Hibernate,您可能会知道它们通过findByExample提供了解决方法,其中您将User作为示例对象提供了查询的属性和值。 使用此示例对象中设置的任何值进行查询,而从查询中排除任何为null字段。 您可以对此行为进行一些调整,但是这种方法存在许多问题。 考虑默认值,必填字段(即无法填写的字段)
null )和不变性。 iBatis,MyBatis以及Spring Data使用代码生成来节省您实现所有这些方法的时间,从而使API膨胀到findBy方法的列表。

这些变通办法可能会走很长一段路,但是它们确实留下了自己的特定问题。 另一种方法是使用lambda。

Lambda可以帮助我们将查询部分与过滤器规范分离。 让我们将findBy函数更改为接受lambda的单个函数。

public interface UserStore {User find(Long id);List<User> findBy(Predicate<User> p);
}

那是一个更好的API。 显然,谓词检查User对象有点天真。 您通常希望使用数据库查询进行过滤。 尽管如此,它仍然很好地满足了本示例的目的,您可以尝试使用自己的lambda来使用数据库查询进行过滤。 [注意: Predicate是Java 8附带的,位于java.util.function包中。

至少在以前的API中,这些谓词被捆绑在一个地方之前,您可能会生气,我们仍然可以捆绑(通用)谓词。 例如,通过创建一个包含它们的实用程序类UserPredicates

public final class UserPredicates {public static Predicate<User> lastname(String matcher) {return candidate -> matcher.equals(candidate.getLastname());}
}

使用新的UserStore API变得非常简单。

static import UserPredicates.lastname;userStore.findBy(lastname("<lastname>");

但是, UserStore中还有一件事确实让我感到困扰。 find(id)函数返回一个用户。 但是,如果没有这样的用户怎么办?

可选的

为了对此进行改进,我们可以(并且应该)查看Java 8的另一个新功能,Optional。 这是monad的Java实现。 它看起来很像Scala的Option

使用Optional我们可以更好地表示一个函数可以返回一个值,但不一定返回一个值,并防止使用null 。 在我们的find(id)示例中,返回Optional明确表示我们可以找到具有所请求ID的用户,但可能不存在这样的用户。

public interface UserStore {Optional<User> find(Long id);List<User> findBy(Predicate p);
}

该API现在不仅记录了您可能会获得用户的事实,而且从未返回null 。 我认为永不返回null的API更安全。 有一天,一个新的程序员可能没有意识到find可以返回null并且结果是一个null指针异常。 只是希望团队能够在生产之前就抓住它。 只要不使用null ,就很容易防止空指针异常。

我们可以使用Optional上的函数从用户那里获取值(如果有),或者从默认值获取。 例如,为了安全地获取用户的姓氏,我们编写以下内容。

Optional<User> user = userStore.find(id);
String lastname = user.map(User::getLastname).orElse("");

这段代码具有很强的表达力,不需要很多解释。 如果有用户,请获取其姓氏。 否则,获取一个空字符串。

如果我们需要向用户发送密码重置电子邮件(如果找到)怎么办?

Optional<User> user = userStore.find(id);
user.ifPresent(passwordReset::send);

如果找到用户,则发送密码重置,否则什么也没有发生。

由于Java不像其他可能提供的其他语言(例如Haskell,Clojure和Scala)那样支持解构,因此我们仅限于Optional的功能。 这使得Optional比其在任何一种语言中的等效性都弱。

建造者

当然,不仅存储库的API都可以从lambda中受益。 Optional也是受益于lambda的API的一个很好的示例。 就我个人而言,我还发现lambda特别有用,可以代替过去的过往建造者。 通常不通过将特定的构建器传递给函数,而是通过从函数中生成一个构建器来改善去耦。 让我向您展示一个示例,用于发送电子邮件以阐明该想法。

public interface Mailer {void sendTextMessage(TextMessageBuilder message);void sendMimeMessage(MimeMessageBuilder message);
}

要使用Mailer我们需要将特定的构建器传递给它。 这些构建器具有通用的界面,但是它们构建的消息类型不同。 Mailer具有不同的方法,因为它必须根据所使用的类型添加不同的信息。 因此,任何客户端代码都紧密耦合以传递正确的构建器。

您可能会怀疑,这是lambda有用的地方。 Mailer函数可以创建所需的生成器并将其产生给lambda,而不是要求客户端创建生成器并将其传递给客户端。

public interface Mailer {void sendTextMessage(MessageConfigurator configurator);void sendMimeMessage(MessageConfigurator configurator);@FunctionalInterfaceinterface MessageConfigurator {MessageBuilder configure(MessageBuilder message);}
}

要使用Mailer我们需要做的就是提供一个lambda来构建消息。

mailer.sendTextMessage(message ->message.from(sender).to(recipients).subject("APIs").body("Lambdas can make for more fluent and stable APIs")
);

API现在更加稳定。 客户端代码与特定构建器中的任何更改都没有关联,只要构建器上的功能保持兼容就不会中断。

正如示例帮助我展示的那样,lambda可以帮助您构建更流畅和稳定的API,这些API更具意图。 这些API不需要太多文档供其他程序员使用,因为实际上很难使他们弄错。 作为一般准则,我更喜欢清晰明了的代码而不是文档。 修正,不记录。

当然,我在本文中仅显示了一些示例。 Lambda不仅适用于此处的示例,而且适用范围更广。 我希望本文能为您提供一些有关lambda可以帮助您的新见解,并希望您能想到它们如何改善您的代码。

参考: Software Craft博客上的JCG合作伙伴 Bart Bakker 提供的Fluent和Stable API的Lambda 。

翻译自: https://www.javacodegeeks.com/2013/11/lambdas-for-fluent-and-stable-apis.html

lambda 加和

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346832.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

攻防世界 适合做桌面_空间“狭小”的二人世界,适合情侣们做浪漫的事情

在最浪漫的11月与它邂逅&#xff0c;有着深秋的枫红、累累的苹果红、还有童话绘本中的苹果屋红&#xff0c;充满着热情活力的色彩&#xff0c;让人感到雀跃。眼瞧见银河的感动。那晚入住于福寿山农场的露营区&#xff0c;位在深山中的它空气轻透又鲜少光害&#xff0c;是观赏星…

使用混合多云每个人都应避免的3个陷阱(第1部分)

每天都在肆意宣传云&#xff0c;但每个人都应避免三个陷阱。 从云&#xff0c;混合云到混合多云&#xff0c;您被告知这是确保业务数字化未来的一种方式。 您必须做出的这些选择不会排除提高客户体验和敏捷交付这些应用程序的日常工作。 让我们开始一段旅程&#xff0c;仔细研…

jquery开关灯案例_全屋开关插座布局讲解,自己规划怕遗漏,手把手教你,很详细...

开关插座是装修内重要的一环&#xff0c;然而也最容易被忽视。装修完住进来后才发现插口不够用&#xff0c;插座被家具挡住&#xff0c;想改还得砸墙&#xff0c;没办法只能用拖线板。然而&#xff0c;满屋都是拖线板&#xff0c;乱糟糟的&#xff0c;看着就惹人烦&#xff0c;…

富贵不压重发_为什么老人常说“贵人不顶重发”,“重发”是什么意思? ?...

"先&#xff0c;""贵人""在我国一般是指有身份有地位有财富的人&#xff0c;而""重发""顾名思义是指头发多的人&#xff0c;那么&#xff0c;老人们为什么会说""贵人不顶重发""呢?有书君认为&#xff0c;可…

java六大原则_六大Java功能

java六大原则我花了无数小时来对不同的应用程序进行故障排除。 通过经验&#xff0c;我可以得出关于大多数开发人员应该远离的几个Java SE功能/ API的结论。 当我提到大多数开发人员时&#xff0c;我会想到常规的Java EE开发人员&#xff0c;而不是库设计人员/基础结构工程师。…

打开虚拟机磁盘类型无效_[图文]VMWARE虚拟机如何打开.VMDK格式的磁盘映像

最近在折腾安卓虚拟机时使用Android x86项目组提供的镜像&#xff0c;架构问题本身无法直接在电脑安装安卓系统。而Android x86项目则是国外团队通过源代码进行移植的版本&#xff0c;虽然不能同步更新但现在也倒是已经 8.1 版。至于折腾安卓虚拟机的原因则是手头的安卓机还是4…

Apache Ivy 2.5.0-rc1发布–现在允许解析器超时

几周前&#xff0c;我们发布了Apache Ivy的2.5.0-rc1版本。 Apache Ivy是一个依赖项管理构建工具&#xff0c;通常与Apache Ant结合使用。 可在项目下载页面上下载 自Apache Ivy的上一版本于2014年12月发布以来&#xff0c;此版本具有重要意义。距上一个正式年份已超过3年。 在…

感量越大抑制频率约低_脉冲信号是什么?它与频率,占空比,正、负逻辑间是什么关系?...

在数字电子系统中&#xff0c;所有传送的信号均为开关量&#xff0c;即只有两种状态的电信号&#xff0c;这种电信号&#xff0c;我们称作做脉冲信号&#xff0c;这是所有数字电路中的基本电信号一个标准的脉冲信号如下图所示。我们把脉冲信号由低电压跳变至高电压的脉冲信号边…

datagrid 小数点_EasyUI 解决 datagrid 中 NumberBox 限制小数位数后不能输入小数点问题...

初始化界面&#xff0c;发现编辑datagrid&#xff0c;不能输入小数点。var arrColumnsCNT [[{title: 毛重,field: GrossWeight,halign: center,width: 60,sortable: true,frozen: true,editor: {type: numberbox,options:{precision:2}}}]];function DefDataGridCNT() {objDat…

【OFDM系列9】OFDM采用正交区分不同子载波的,但是子载波通过调相后携带了基带信号后,如何还能继续保证两者正交

不经意间在知乎看到这样一个问题&#xff0c;在此记录一下我的看法 OFDM采用正交区分不同子载波的&#xff0c;但是子载波通过调相后携带了基带信号后&#xff0c;如何还能继续保证两者正交&#xff1f; 补充内容是&#xff1a;OFDM是指通过2组正交载波传递信息&#xff0c;但…

使用threadlocal_何时以及如何使用ThreadLocal

使用threadlocal正如我们的读者可能已经猜到的那样&#xff0c;我每天都会处理内存泄漏。 最近&#xff0c;一种特殊类型的OutOfMemoryError消息开始引起我的注意-滥用ThreadLocals引发的问题变得越来越频繁。 在查看此类泄漏的原因时&#xff0c;我开始相信其中一半以上是由于…

企业为什么要开通银企直联_企业为什么要做网站推广

随着现代社会的发展&#xff0c;如果企业不做网站推广&#xff0c;那么可以说是寸步难行&#xff0c;今天就来为大家说说企业为什么一 定要做网站推广的详情&#xff01;1 、网络品牌推广做网络营销的结果就是在互联网要有自己的品牌&#xff0c;并且可以再网络上得到无限性的延…

在Java错误产生之前对其进行处理的新方法

我们如何认识到解决预生产错误的旧方法还不够&#xff0c;以及我们如何能够改变这种情况 第一次尝试时就没有完美的代码&#xff0c;我们所有人都可以证明我们已经学到了很难的方法。 不管我们使用多少测试周期&#xff0c;代码审查或工具&#xff0c;总有至少一个偷偷摸摸的错…

学术诚信的重要性_申论作文开头之诚信

本段是经典开头或过渡段落写作&#xff0c;通过反面论证引出总论点重要性&#xff0c;结构清晰&#xff0c;层次感强&#xff0c;本段可以适用于公民道德与诚信建设问题、食品安全问题、环境污染等等&#xff0c;其中影响及重要性分析语句可以用于申论作文的开头部分&#xff0…

curl 访问不到html_嵌入式工程师入门前后端系列1:访问一个网页

做为嵌入式行业的从业者&#xff0c;最近经常听到PAAS&#xff0c;SAAS等和”云”相关的概念&#xff0c;被整的一头雾水。很多时候咱们的物联网硬件设备都会有一个云平台&#xff0c;用于设备管理或者UI应用展示等功能&#xff0c;这通常是由专门的前后端工程师配合美工一起完…

java:8最小镜像_Java:本地最小语言

java:8最小镜像在1996年至2002年之间&#xff0c;我用Java编写了成千上万行代码。我用Java 1.0到Java 1.4编写了Web框架&#xff0c;电子表格以及更多内容。 与90年代中期&#xff08;预模板&#xff09;的C 相比&#xff0c;Java是一种完全令人惊奇的语言。 JVM是所有计算机语…

seaborn无法import_无法导入seaborn

我在进口seaborn时有问题。我最近在我的电脑上安装了“Python”&#xff0c;并尝试使用seaborn pacjesge。我更新了scipy和{}。实际上&#xff0c;在更新scipy之前&#xff0c;python看不到{}。问题是什么&#xff1f;请帮帮我Python 2.7.10 |Anaconda 2.3.0 (64-bit)| (defaul…

project子项目之间任务关联_project项目任务类型,就这么简单

任务是Project中最重要的概念之一&#xff0c;它是组成项目的基本元素。在Project项目管理软件中&#xff0c;任务的类型被分为三类&#xff0c;它们分别是固定单位任务&#xff0c;固定工期任务和固定工时任务。对这些任务类型的认识和了解&#xff0c;项目团队可以充分的协调…

邪恶的Java技巧使JVM忘记检查异常

我长期以来一直批评Java中的编译器检查异常机制。 无论您是爱还是恨&#xff0c;都可以肯定一件事&#xff1a;在某些情况下&#xff0c;您不想与他们打交道。 Java中的解决方案是将一个检查过的异常包装在new RuntimeException(e)但这可以提供较长的堆栈跟踪&#xff0c;而无需…

盲僧一键r闪用什么设置_美加狮R.A.T. PRO X3至尊版带你畅玩模拟飞行

很多模拟飞行或者皇牌空战的玩家们都追求在游戏过程中的真实驾驶体验&#xff0c;渴望通过游戏来实现自己的飞行梦。但普通鼠标的左右键及滚轮并不能带给玩家逼真的体验&#xff0c;美加狮全新发布的鼠标R.A.T. PRO X3至尊版却可以做到。美加狮R.A.T. PRO X3至尊版是美加狮全新…