功能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 webservice
  DocumentDb documentDb

  void 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.id
          doc.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 webservice
  DocumentDb documentDb

  void 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.id
        doc.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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值