功能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)语言,都被设计为主要支持),开发人员编写了计算机所需的确切语句。执行以完成特定任务。

一些非常命令性 (过程性)代码的信号:

  1. 专注于如何执行任务
  2. 状态更改和执行顺序很重要
  3. 许多循环和条件

该代码明确地集中在“如何”上,这使得“什么”难以确定。

专注于什么

就像本文的标题一样,我们的第一步是从命令式的编码和重构方式转变为更具声明性的样式-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 -&gt; doc.type == 'important' } if (doc.type == 'important') findAll { doc -&gt; doc.type == 'important' } findAll { doc -&gt; doc.type == 'important' }再次涉及文档集合本身- 意思是“查找所有重要的文档,并仅返回那些重要文档的新集合”
  • 强制性的for-loop (带有中间的i变量)已由文档集合本身上的声明性的each方法所代替- 意思是“为列表中的每个文档执行一段代码,我不在乎您如何执行” &#55357;&#56898;

不用担心eachfindAll :这些方法是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

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

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

相关文章

python怎样使用各个日期赤纬_python--日期操作

import datetimedatetime有几个常用类:date time datetime timedelta1. 今天日期时间(今天时间)>>> import datetime>>> now datetime.datetime.now()>>> print now2014-06-04 21:08:32.952591(今天日期)>>> print datetime…

常用的光电模块SFP、QSFP等解析

前言 学习记录 BNC 是用来接同轴电缆的接口&#xff0c;好处是降低了信号之间的相互干扰&#xff1b;主要市场是安防行业以及一些使用同轴电缆作为传输介质的令牌以太网。举个例子就是小时候的电视机后面经常能够看见这种线&#xff0c;BNC接头中间有一个凸起来的针&#xff…

python最短路径例子_Python实现的多叉树寻找最短路径算法示例

本文实例讲述了Python实现的多叉树寻找最短路径算法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;多叉树的最短路径&#xff1a;思想&#xff1a;传入start 和 end 两个 目标值1 找到从根节点到目标节点的路径2 从所在路径&#xff0c;寻找最近的公共祖先节点&#…

零分钟即可在容器开发套件(CDK)上实现云运营

尽管这很有趣&#xff0c;但实际上并不可行&#xff0c;很快就遇到了使用限制。前一段时间&#xff0c; 我逐步完成了在容器中安装称为CloudForms的云管理解决方案。 真正的解决方案是将这个示例放入Red Hat Demo Central集合中&#xff0c;并将其放在基于开放技术的Cloud解决…

NTPv4协议解析

前言 本文的撰写基于RFC5905.NTP 是时间网络控制协议&#xff0c;V4版本相交V3版本&#xff0c;修复了V3存在的一些问题。尤其是NTPV4的拓展时间戳鼓励使用浮动双数据类型&#xff0c;这样使得NTP能够更好的支持1ns的场景&#xff0c;轮询间隔也从上一代的最多1024s拓展到了36…

c++中的引用和python中的引用_【总结】C++、C#、Java、Javascript、Python中引用的区别...

首先分两大阵营&#xff1a;C中引用是一块阵营&#xff0c;C#、Java、Javascript、Python中引用是另一块阵营。之所以这样分是因为同一阵营中引用使用方法基本一样。C引用本质是个常量指针&#xff0c;而其他语言引用本质是个普通指针。也就意味着C的引用一旦初始化(指向确定了…

看完这篇还不会化简卡诺图?你来打我

最通俗易懂的的卡诺图化简教程 首先我们来介绍一下什么是卡诺图&#xff1a; 卡诺图是逻辑函数的一种图形表示。一个逻辑函数的卡诺图就是将此函数的最小项表达式中的各最小项相应地填入一个方格图内&#xff0c;此方格图称为卡诺图。 卡诺图的构造特点使卡诺图具有一个重要性…

javabean 连接mysql_连接mysql的javabean实例+简单分页

连接mysql的javabean实例简单分页rs.getString(user_id)rs.getString(user_name)rs.getString(user_mail)rs.getString(user_adds)int Cint(String cint){try {int n;n Integer.parseInt(cint);return n;}catch (NumberFormatException e) {return 0;}}%>int PageSize5; //设…

java 工厂方法模式_Java中的工厂方法模式

java 工厂方法模式在上一篇有关模板方法模式的文章中 &#xff0c;我展示了如何利用lambda表达式和默认方法 。 在本文中&#xff0c;我将探讨工厂方法模式&#xff0c;并了解如何利用方法引用&#xff0c;这是Java 8中与lambda表达式一起添加的另一项功能。 让我们考虑一个Ve…

几种常见的集成触发器(D、T、JK)

同步RS触发器存在“空翻”现象&#xff0c;即触发器存在多次翻转的现象&#xff0c;空翻破坏了“时序电路按时钟节拍工作&#xff0c;每个时钟脉冲作用下电路的状态只发生一次转换”的基本原则 解决方法&#xff1a;将电平触发改为边沿触发&#xff0c;使得触发器旨在时钟脉冲…

mysql md5版本校验_MySQL查询以名称的md5版本更新所有条目?

为此&#xff0c;您可以使用MD5()。让我们首先创建一个表-mysql> create table DemoTable1887(Password text,HashPassword text);使用插入命令在表中插入一些记录-mysql> insert into DemoTable1887(Password) values(John9089);mysql> insert into DemoTable1887(Pa…

Hashcat从入门到入土(一)

Hashcat的官方是这么介绍自己的 Hashcat is a password recovery tool. It had a proprietary code base until 2015, but was then released as open source software. Versions are available for Linux, OS X, and Windows. Examples of hashcat-supported hashing algorith…

MySQL在哪里看secret_key_K8S 创建和查看secret(九)

yaml中的用户密码敏感信息一般都会采用密码存储采用base64编码进行加密[roothz-95 pv]# echo -n guang | base64emd1YW5nag[roothz-95 pv]# echo -n 1q2w#E$R | base64cat secret.ymalapiVersion: v1kind: Secretmetadata:name: mysecret2data:username: emd1YW5nagpassword: M…

java 语义_Java文件合并变得语义化

java 语义与任何程序员交谈&#xff0c;并询问他应该如何进行合并&#xff1a;“它应该理解代码&#xff0c;对其进行解析&#xff0c;然后根据结构进行合并” –他很可能会说。 而这恰恰是SemanticMerge for Java所做的&#xff1a;它解析要合并的文件&#xff08;加上祖先或…

python循环指令_Python循环

布尔运算学习循环之前&#xff0c;先了解一个概念&#xff1a;布尔运算布尔运算是数字符号化的逻辑推演法&#xff0c;包括联合、相交、相减。在图形处理操作中引用了这种逻辑运算方法以使简单的基本图形组合产生新的形体&#xff0c;并由二维布尔运算发展到三维图形的布尔运算…

Apache Pulsar:分布式发布订阅消息系统

Apache Pulsar是一个开源的分布式pub-sub消息传递系统&#xff0c;最初由Yahoo创建&#xff0c;并且是Apache Software Foundation的一部分 。 Pulsar是用于服务器到服务器消息传递的多租户高性能解决方案。 脉冲星的主要功能包括[4]&#xff1a; 对Pulsar实例中的多个集群的…

查看mysql进程ps_linux ps命令查看当前运行的进程

Linux中的ps命令是Process Status的缩写。ps命令用来列出系统中当前运行的那些进程。ps命令列出的是当前那些进程的快照&#xff0c;就是执行ps命令的那个时刻的那些进程&#xff0c;如果想对进程进行实时的监控&#xff0c;应该用 top 命令。要对进程进行监测和控制&#xff0…

java获取文件编码_java如何获取文件编码格式

1&#xff1a;简单判断是UTF-8或不是UTF-8&#xff0c;因为一般除了UTF-8之外就是GBK&#xff0c;所以就设置默认为GBK。按照给定的字符集存储文件时&#xff0c;在文件的最开头的三个字节中就有可能存储着编码信息&#xff0c;所以&#xff0c;基本的原理就是只要读出文件前三…

java上传文件功能_Java MemoryMapped文件的功能

java上传文件功能Java MemoryMapped文件的功能 在JDK 1.4中&#xff0c;内存映射文件的一个有趣功能被添加到Java中&#xff0c;该功能允许将任何文件映射到OS内存以进行有效读取。 内存映射文件可用于开发IPC类型的解决方案。 本文是使用内存映射文件创建IPC的实验。 有关内存…

java代码快速_java代码编写快捷途经

CtrlR 然后按下R键SHiftAltR&#xff1a;对选定属性进行全局命名CtrlD:删除当前行CtrlQ&#xff1a; 定位到最后编辑的地方CtrlL&#xff1a; 定位在某行CtrlM&#xff1a; 最大化当前的 Edit(命令)CtrlO&#xff1a;快速显示大纲CtrlD&#xff1a;显示继承结构CtrlW :关掉当…