java 示例_功能Java示例 第4部分–首选不变性

java 示例

这是称为“ Functional Java by Example”的系列文章的第4部分。

在上一部分中,我们讨论了一些副作用,并且我想进一步详细说明如何通过不可变性引入代码中来防止意外地对数据进行操作。

如果您是第一次来,最好是从头开始阅读。

它有助于了解我们从何处开始以及如何在整个系列中继续前进。

这些都是这些部分:

  • 第1部分–从命令式到声明式
  • 第2部分–讲故事
  • 第3部分–不要使用异常来控制流程
  • 第4部分–首选不变性
  • 第5部分–将I / O移到外部
  • 第6部分–用作参数
  • 第7部分–将失败也视为数据
  • 第8部分–更多纯函数

我将在每篇文章发表时更新链接。 如果您通过内容联合组织来阅读本文,请查看我博客上的原始文章。

每次代码也被推送到这个GitHub项目 。

纯功能

关于我们之前讨论的内容的小结。

  • 函数式编程鼓励使用无副作用的方法(或:函数),以使代码更易理解且易于推理 。 如果某个方法仅接受某些输入并每次都返回相同的输出(这使其成为一个函数),则各种优化都可以在后台进行,例如通过编译器或缓存,并行化等。
  • 我们可以再次用函数的(计算出的)值代替函数,这称为参考透明度 。

这是上一部分重构后当前的内容:

class FeedHandler {Webservice webserviceDocumentDb documentDbvoid handle(List<Doc> changes) {changes.findAll { doc -> isImportant(doc) }.each { doc ->createResource(doc).thenAccept { resource ->updateToProcessed(doc, resource)}.exceptionally { e ->updateToFailed(doc, e)}}}private CompletableFuture<Resource> createResource(doc) {webservice.create(doc)}private boolean isImportant(doc) {doc.type == 'important'}private void updateToProcessed(doc, resource) {doc.apiId = resource.iddoc.status = 'processed'documentDb.update(doc)}private void updateToFailed(doc, e) {doc.status = 'failed'doc.error = e.messagedocumentDb.update(doc)}}

我们的updateToProcessedupdateToFailed是“不纯的”-它们都将更新现有文档in 。 正如你可以通过它们的返回类型,见void ,在Java中,这表示:没有出来 。 下沉Kong。

private void updateToProcessed(doc, resource) {doc.apiId = resource.iddoc.status = 'processed'documentDb.update(doc)
}private void updateToFailed(doc, e) {doc.status = 'failed'doc.error = e.messagedocumentDb.update(doc)
}

这些类型的方法都围绕您的典型代码库。 因此,随着代码库的增长,在将数据传递给这些方法之一后,往往很难对数据的状态进行推理。

请考虑以下情形:

def newDocs = [new Doc(title: 'Groovy', status: 'new'),new Doc(title: 'Ruby', status: 'new')
]feedHandler.handle(newDocs)println "My new docs: " + newDocs
// My new docs: 
// [Doc(title: Groovy, status: processed),
//  Doc(title: Ruby, status: processed)]
// WHAT? My new documents aren't that 'new' anymore

罪魁祸首一直在破坏我文件的地位; 首先,它们是“新的”,其次不是。 那不行! 一定是该死的FeedHandler。 谁创作的东西? 为什么会触碰我的数据?

考虑另一种情况,即有多个参与者处理您的业务。

def favoriteDocs = [new Doc(title: 'Haskell'),new Doc(title: 'OCaml'),new Doc(title: 'Scala')
]archiver.backup(favoriteDocs)feedHandler.handle(favoriteDocs)mangleService.update(favoriteDocs)userDao.merge(favoriteDocs, true)println "My favorites: " + favoriteDocs
// My favorites: []
// WHAT? Empty collection? Where are my favorites????

我们从一组项目开始,然后通过4种方法发现我们的数据不见了。

在每个人都可以改变任何事物的世界中,很难在任何给定时间推断任何状态。

它本身甚至还不是“全局状态”,任何拥有(引用到)数据的人都可以清除传递给方法的集合,并可以更改变量。

首选不变性

那是什么 如果对象在实例化后不更改其状态,则该对象是不可变的。

看起来合理吧?

不变性 图片来源: 应对并适应持续变化

关于如何使用您的特定语言进行操作,这里有大量资源。 例如,Java默认不支持不变性。 必须做些工作。

如果有第三方在处理过程中发生问题并更改数据(例如清除我的收藏夹),则可以通过将我的收藏夹传递到不可修改的包装中来快速清除麻烦制造者,例如

def data = [...
]// somewhere inside 3rd-party code
data.clear()// back in my code:
// data is empty *snif*

预防故障:

def data = Collections.unmodifiableCollection([])// somewhere inside 3rd-party code
data.clear() // HAHAA, throws UnsupportedOperationException

在您自己的代码库中,我们可以通过最小化可变数据结构来防止意外的副作用(例如,我的数据在某处更改)。

在大多数FP语言中,例如Haskell , OCaml和Scala ,默认情况下 ,语言本身会促进不变性 。 虽然不是真正的FP语言,但使用ES6编写不可变JavaScript也趋于成为一种好习惯。

首先只读

使用到目前为止所学的原理,并努力防止意外的副作用,我们希望确保实例化实例后, 不能Doc类进行任何更改 ,甚至不能对updateToProcessed / updateToFailed方法进行更改

这是我们当前的课程:

class Doc {String title, type, apiId, status, error
}

Groovy不需要进行使Java类变为不可变的所有手动工作,而是借助Immutable -annotation进行了抢救。

当放置在类上时,Groovy编译器进行了一些增强,因此创建后再也没有人可以更新其状态。

@Immutable
class Doc {String title, type, apiId, status, error
}

该对象实际上变为“只读”,并且任何尝试更新属性的操作都将导致恰当命名的ReadOnlyPropertyException

private void updateToProcessed(doc, resource) {doc.apiId = resource.id // BOOM! // throws groovy.lang.ReadOnlyPropertyException: //  Cannot set readonly property: apiId...
}private void updateToFailed(doc, e) {doc.status = 'failed' // BOOM! // throws groovy.lang.ReadOnlyPropertyException: //  Cannot set readonly property: status...
}

但是,等等,这是否意味着updateToProcessed / updateToFailed方法实际上将无法将文档status更新为“已处理”或“失败”?

吉普,这就是不变性带给我们的。 如何修复逻辑?

复制第二

Haskell关于“不可变数据”的指南为我们提供了有关如何进行操作的建议:

纯功能程序通常在不可变数据上运行。 代替更改现有值,而是创建更改的副本并保留原始副本。 由于结构的未更改部分无法修改,因此它们通常可以在旧副本和新副本之间共享,从而节省了内存。

答:我们克隆它!

我们没有更新的原始数据,我们应该做的一个副本-原来不是我们的,应保持不变。 我们的Immutable -annotation支持一个名为copyWith的参数。

@Immutable(copyWith = true)
class Doc {String title, type, apiId, status, error
}

因此,我们将更改方法以制作状态已更改 (以及api id和错误消息) 的原始副本,返回此副本

(总是返回Groovy方法中的最后一条语句,不需要显式的return关键字)

private Doc setToProcessed(doc, resource) {doc.copyWith(status: 'processed',apiId: resource.id)
}private Doc setToFailed(doc, e) {doc.copyWith(status: 'failed',error: e.message)
}

数据库逻辑也已上移,将返回的副本存储起来。

我们已经控制了我们的状态!

现在就这样

如果您以Java程序员的身份担心过多的对象实例化对性能的影响,请在此处发表一篇令人放心的文章 。

作为参考,这是重构代码的完整版本。

class FeedHandler {Webservice webserviceDocumentDb documentDbvoid handle(List<Doc> changes) {changes.findAll { doc -> isImportant(doc) }.each { doc ->createResource(doc).thenAccept { resource ->documentDb.update(setToProcessed(doc, resource))}.exceptionally { e ->documentDb.update(setToFailed(doc, e))}}}private CompletableFuture<Resource> createResource(doc) {webservice.create(doc)}private boolean isImportant(doc) {doc.type == 'important'}private Doc setToProcessed(doc, resource) {doc.copyWith(status: 'processed',apiId: resource.id)}private Doc setToFailed(doc, e) {doc.copyWith(status: 'failed',error: e.message)}}

翻译自: https://www.javacodegeeks.com/2018/06/functional-java-part-4-immutability.html

java 示例

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

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

相关文章

SVN merge(合并) 的三种方式

文章目录一、合并一个范围的版本&#xff08;Merge a range of revisions&#xff09;二、复兴合并&#xff08;Reintegrate a branch&#xff09;三、合并两个不同的树&#xff08;Merge two different trees&#xff09;四、实例五、总结合并的工作是 把主干或者分支上合并范…

php主机安装v2,RackTables 安装教程Installation GuideV2

RackTables安装教程 V1.01.准备一份Ubuntu 12.04.01 LTS的 ISO (系统最好用Ubuntu的版本&#xff0c;简单实用)。2.安装操作系统, 功能选中OPENSSH SERVER (开启SSH)和 LAMP SERVER &#xff0c;注意在LAMP安装过程中会提示MySQL的ROOT密码&#xff0c;这个密码很重要&#xff…

java延时执行_Java谓词的延迟执行

java延时执行在先前的文章“ 用Java的供应商延迟执行 ”和“ Java的消费者延迟执行 “&#xff0c;我看着很容易地通过推迟标准Java API接受&#xff0c;分别在Java执行供应商 S和消费者秒。 在本文中&#xff0c;我将对标准JDK提供的API如何通过标准功能接口Predicate允许延迟…

Mac 如何彻底删除/卸载程序

卸载某些应用程序后会留下一些预置文件和缓存等&#xff0c;一般这些文件没有潜在坏处&#xff0c;不过有些文件的存在也会导致无法正常安装新版本&#xff0c;你可以删除它们来彻底跟该应用程序说拜拜。这些文件通常位于以下路径&#xff1a; ~/Library/Application Support/…

air java,Java Bean

1.Java Bean 简介Java Bean (也称为Bean) 是一个遵循特定写法的Java类&#xff0c;只不过这个类需要遵循一些编码的约定&#xff0c;通常具有如下特点&#xff1a;1).它是一个公开的(public)类&#xff1b;2).它有一个默认的构造方法&#xff0c;也就是不带参数的构造方法(在实…

如何理解Java的类变量、成员变量、常量、类属性、实例属性、字段(field)、成员方法、类方法

文章目录变量相关概念变量/常量类变量/静态变量成员变量/实例变量类属性/实例属性/对象属性什么是 field成员变量和类变量的区别两个变量的生命周期不同访问方式不同数据存储位置不同方法相关概念示例代码判断题变量相关概念 变量/常量 所谓变量就是指可以改变的数据量&#…

无处不再的广告_我的机器人现在无处可去。 无家可归。 无服务器。

无处不再的广告我通常会关注各种网站-最新出版物&#xff0c;热门新报价&#xff0c;限时游戏和竞赛等。 其中大多数不提供“干净”的通知系统&#xff0c;例如RSS feed。 因此&#xff0c;我经常不得不刮擦他们HTML才能达到我的需求。 这意味着我经常需要运行一些自定义的字…

java service实例,javaweb后端实例 service

service的作用1.将前端需要的业务代码封装成接口2.将do数据封装为vo3.水平有限只知道这些下面展示的代码为将do封装为vopublic class StationService { private StationDao stationDao new StationDao(); public List listSLByYear(int year) { //创建vo链表 List list new L…

前端 JS 如何在一个页面中局部加载其它页面的数据

一个页面很大&#xff0c;可以分成多个部分&#xff0c;先把小部分的 jsp 写好之后&#xff0c;再在主页面中通过 Struts 2 标签或 ajax 请求来引入其它的 jsp 显示信息。 通过 jQuery 函数来加载其它页面的数据 <script> $(function () {$("#new").load(&qu…

switch字符串jdk_应用新的JDK 11字符串方法

switch字符串jdk在“ 使用JDK 11的Java字符串上的新方法 ”和“ String&#xff03;repeat即将加入Java&#xff1f; ”&#xff0c;我讨论了JDK 11引入Java String的六种新方法。 可用的早期访问JDK 11构建已经包含了这些新方法&#xff0c;在这篇文章中&#xff0c;我将使用…

aws lambda使用_使用AWS Lambda的CloudWatch事件通知

aws lambda使用CloudWatchEvents的主要用例是跟踪整个AWS基础架构中的更改。 当前&#xff0c;它支持跨Auto Scaling组&#xff0c;EC2&#xff0c;EBS和其他各种事件发出的事件。 为了对这些事件进行有意义的处理&#xff0c;我们需要一种消耗它们的方法。 AWS使用术语“ targ…

Struts2中的OGNL表达式和ValueStack

文章目录OGNL 是干什么用的示例代码一示例代码二使用OGNL获取JavaBean对象的属性值获取集合属性中元素的属性的值XWork 中对 OGNL 的扩展示例代码Struts2 对 OGNL 的封装OGNL 可以用在哪些地方OGNL 的结构示意图XWork 对 OGNL 改造后的结构示意图Struts 2 对 OGNL 改造后的结构…

matlab画图五角星标记,Matlab---画图线型、符号及颜色

Matlab 画图线形、颜色、数据点形状的选择1&#xff0c;线形- Solid line (default)-- Dashed line: Dotted line-. Dash-dot line2&#xff0c;颜色r Redg Greenb Bluec Cyanm Magentay Yellowk Blackw White3&#xff0c;数据点的形状 Plus signo Circle* Asterisk. Pointx C…

php 淘宝客接口开发,如何使用PHP的curl函数调用维易淘客接口

《如何使用PHP的curl函数调用维易淘客接口》要点&#xff1a;使用curl调用维易淘客接口高佣转链维易淘客接口是用GET方式调用的&#xff0c;直接用GET调用即可&#xff0c;以下用PHP为例&#xff1a;使用curl调用维易淘客接口高佣转链&#xff1a;$apihttp://api.vephp.com/hca…

querydsl 转字符串_QueryDSL中包含通配符的字符串的精确匹配

querydsl 转字符串在我们最近的一个项目中&#xff0c;我们的客户要求一个搜索字段&#xff0c;该字段可以搜索名字&#xff0c;姓氏和电子邮件地址&#xff0c;唯一的通配符是星号“ *”&#xff0c;表示部分匹配。 听起来很简单&#xff0c;但这使我们陷入了混乱。 在我们的项…

Java中,我自己定义的某个类,去实现某个接口,是否必须实现该接口的全部抽象方法呢?

不一定&#xff0c;关键要看子类是否是抽象类。 如果子类是非抽象类&#xff0c;则必须实现接口中的所有方法&#xff1b;如果子类是抽象类&#xff0c;则可以不实现接口中的所有方法&#xff0c;因为抽象类中允许有抽象方法的存在&#xff01; 一、抽象类定义 抽象类往往用…

堆栈溢出 java_堆栈溢出回答了我们所不知道的Java首要问题

堆栈溢出 java您不应该错过的堆栈溢出问题集合&#xff1a; 这不是秘密&#xff1b; 我们都使用堆栈溢出。 它拥有生命&#xff0c;宇宙和几乎所有与代码相关的答案。 该平台为开发人员&#xff0c;工程师和其他人员提供了一个找到他们所面临问题的答案的地方&#xff0c;或者…

Java 的面向接口编程

假设有这样的代码&#xff1a; F f new G(); f.do(); f.cook(); ...F 是一个接口&#xff0c;G 是 F 的一个实现类&#xff08;也叫具体类/派生类&#xff09;。 如果现在需要另外一个实现类 H 采用其他技术实现接口 F 的所有抽象方法&#xff0c;那么只要修改一条代码&…

mysql 表数据diff,mysqldiff使用笔记

背景手上有个项目&#xff0c;有三个环境:本地开发,测试环境,线上环境&#xff0c;历史原因怀疑数据库表字段可能出现不匹配&#xff0c;所以寻找合适的工具比较数据库表结构。找到了mysqldiff。准备工具正好手上有台windows机器&#xff0c;使用windows版本测试安装mysqldiff是…

java超出gc开销_通过这5个简单的技巧减少GC开销

java超出gc开销编写代码的五种简单方法&#xff0c;可以提高内存效率&#xff0c;而无需花费更多时间或降低代码可读性 垃圾回收会为您的应用程序增加多少开销&#xff1f; 您可能不知道确切的数字&#xff0c;但您确实知道总有改进的余地。 尽管自动GC是最有效的过程&#x…