为什么声明性编码使您成为更好的程序员

在许多情况下,具有功能组成的声明式解决方案提供了优于传统命令式代码的优越代码度量。 阅读本文并了解如何使用具有功能组成的声明性代码成为更好的程序员。

在本文中,我们将仔细研究三个问题示例,并研究用于解决这些问题的两种不同技术(命令式和声明式)。

本文中的所有源代码都是开源的,可以在以下位置获得
https://github.com/minborg/imperative-vs-declarative 。 最后,我们还将看到如何将本文的知识应用于数据库应用程序领域。 我们将使用Speedment Stream作为ORM工具,因为它提供了与数据库中的表,视图和联接相对应的标准Java Streams,并支持声明性构造。

从字面上看,有无数个示例候选可用于代码度量评估。

问题范例

在本文中,我选择了开发人员在工作期间可能会遇到的三个常见问题:

SumArray

遍历数组并执行计算

分组

并行汇总值

休息

通过分页实现REST接口

解决技术

正如本文开头所暗示的,我们将使用以下两种编码技术来解决上述问题:

势在必行

一种命令式解决方案,其中我们使用带有for循环和显式可变状态的传统代码样式。

陈述式

声明性解决方案,其中我们组合了各种功能以形成可以解决问题的高阶复合功能,通常使用
java.util.stream.Stream或其变体。

代码指标

然后,想法是使用适用于SonarQube(此处为SonarQube社区版,版本7.7)的不同解决方案的静态代码分析,以便我们可以为问题/解决方案组合得出有用的标准化代码度量。 然后将这些指标进行比较。

在本文中,我们将使用以下代码指标:

LOC

“ LOC”表示“代码行”,是代码中非空行的数量。

陈述

是代码中语句的总数。 每条代码行上可能有零到多条语句。

圈复杂度

指示代码的复杂性,是对通过程序源代码的线性独立路径数量的定量度量。 例如,单个“ if”子句在代码中提供了两条单独的路径。
了这里的维基百科。

认知复杂性

SonarCube声称:“认知复杂性不同于使用数学模型评估软件可维护性的实践。 它从Cyclomatic Complexity设定的先例开始,但是使用人工判断来评估应如何计算结构并决定应向模型整体添加哪些内容。 结果,它得出的方法复杂性得分比以前的模型更能使程序员对可维护性进行相对公平的评估。” 在SonarCube自己的页面上了解更多信息 。

通常,最好构想一个解决方案,其中这些指标较小,而不是较大。

作为记录,应该注意的是,以下设计的任何解决方案只是解决任何给定问题的一种方法。 让我知道您是否有更好的解决方案,并随时通过https://github.com/minborg/imperative-vs-declarative提交拉取请求。

遍历数组

我们从一个简单的开始。 该问题示例的对象是计算int数组中元素的总和,并将结果返回为
long 。 以下接口定义了问题:

 public interface SumArray { long sum( int [] arr);  } 

当务之急

以下解决方案使用命令式技术实现SumArray问题:

 public class SumArrayImperative implements SumArray { @Override public long sum( int [] arr) { long sum = 0 ; for ( int i : arr) { sum += i; } return sum; }  } 

声明式解决方案

这是使用声明性技术实现SumArray的解决方案:

 public class SumArrayDeclarative implements SumArray { @Override public long sum( int [] arr) { return IntStream.of(arr) .mapToLong(i -> i) .sum(); }  } 

注意, IntStream::sum只返回一个int,因此我们必须应用中间操作mapToLong()

分析

SonarQube提供以下分析:

下表显示了SumArray的代码指标(通常越低越好):

技术 LOC 陈述 圈复杂度 认知复杂性
势在必行 12 5 2 1个
功能性 11 2 2 0

这是它在图形中的外观(通常越低越好):

并行汇总值

该问题示例的对象是将“ Person对象分组到不同的存储桶中,其中每个存储桶构成一个人的出生年份和一个工作的国家/地区的唯一组合。对于每个组,应计算平均工资。 聚合应使用公共ForkJoin池并行计算。

(不变的) Person类是这样的:

势在必行

我们还定义了另一个称为YearCountry不变类,该类将用作分组键:

势在必行

定义了这两个类之后,我们现在可以通过以下接口定义此问题示例:

势在必行

当务之急

GroupingBy示例问题实施命令式解决方案并非难事。 这是解决问题的一种解决方案:

势在必行

声明式解决方案

这是一个使用声明性构造实现GroupingBy的解决方案:

势在必行

在上面的代码中,我使用了一些静态导入
Collectors类(例如Collectors::groupingBy )。 这不会影响代码指标。

分析

SonarQube提供以下分析:

下表显示了GroupingBy的代码指标(越低越好):

技术 LOC 陈述 圈复杂度 认知复杂性
势在必行 52 27 11 4
功能性 17 1个 1个 0

相应的图形如下所示(通常越低越好):

实施REST接口

在这个示例性问题中,我们将为Person对象提供分页服务。 出现在页面上的人员必须满足某些(任意)条件,并且必须按照给定的顺序进行排序。 该页面应作为不可修改的“个人”对象列表返回。

这是捕获问题的接口:

势在必行

页面的大小在一个单独的实用程序类RestUtil

势在必行

当务之急

这是Rest接口的命令性实现:

势在必行

声明式解决方案

下列类以声明的方式实现Rest接口:

势在必行

分析

SonarQube提供以下分析:

下表显示了Rest的代码指标(通常越低越好):

技术 LOC 陈述 圈复杂度 认知复杂性
势在必行 27 10 4 4
功能性 21 1个 1个 0

在这里,相同的数字显示在图表中(再次降低通常会更好):

Java 11的改进

上面的示例是用Java 8编写的。使用Java 11,我们可以使用LVTI(局部变量类型推断)来缩短声明性代码。 这会使我们的代码短一些,但不会影响代码指标。

势在必行

与Java 8相比,Java 11包含一些新的收集器。 例如,
Collectors.toUnmodifiableList()可以使我们的声明式Rest解决方案更短:

势在必行

同样,这不会影响代码指标。

摘要

对我们的三个示例性问题的代码度量取平均会得出以下结果(通常越低越好):

考虑到本文的输入要求,当我们从命令式构造到声明式构造时,所有代码度量都有显着改进。

在数据库应用程序中使用声明性构造

为了从数据库应用程序中获得声明式构造的好处,我们使用了Speedment Stream 。 Speedment Stream是基于Stream的Java ORM工具,可以将任何数据库表/视图/联接转换为Java流,从而使您可以在数据库应用程序中运用声明性技能。

您的数据库应用程序代码将变得更好。 实际上,针对数据库的具有Speedment和Spring Boot的分页REST解决方案可能表示如下:

势在必行

Speedment提供Manager<Person> persons ,并构成数据库表“ Person”的句柄,并且可以通过Spring @AutoWired进行管理。

结论

选择声明式而不是命令式解决方案可以大大降低通用代码的复杂性,并可以提供许多好处,包括更快的编码,更好的代码质量,提高的可读性,更少的测试,减少的维护成本等等。

为了从数据库应用程序中的声明性构造中受益,Speedment Stream是一种可以直接从数据库提供标准Java Streams的工具。

如今,对于任何当代的Java开发人员来说,必须掌握声明性构造和功能组成。

资源资源

文章源代码: https : //github.com/minborg/imperative-vs-declarative

SonarQube: https ://www.sonarqube.org/ Speedment Stream: https ://speedment.com/stream/ Speedment初始化程序: https ://www.speedment.com/initializer/

翻译自: https://www.javacodegeeks.com/2019/08/declarative-coding-makes-better-programmer.html

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

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

相关文章

高效的企业测试-单元和用例测试(2/6)

在本系列的第一部分中&#xff0c;我们看到了有效测试应满足的一些普遍适用的原则和约束。 在这一部分中&#xff0c;我们将仔细研究代码级单元测试以及组件或用例测试。 单元测试 单元测试验证单个单元&#xff08;通常是类&#xff09;的行为&#xff0c;而忽略或模拟该单元…

搜狗输入法更换字体与皮肤

图标上右键-更多-属性设置 效果&#xff1a; 注意&#xff1a;如果是新安装的字体&#xff0c;更换中文字体但其中列表没有显示&#xff0c;可以取消更换字体前面的对钩后&#xff0c;重新选择对钩&#xff0c;此时就显示新的中文字体了

javafx 8u40_JavaFX 8u20天的未来过去(始终在最前面)

javafx 8u40自从我发布有关JavaFX的主题以来已经有很长时间了。 因此&#xff0c;如果您仍在追随&#xff0c;那就太棒了&#xff01; 介绍 在这篇博客文章中&#xff0c;我想写一篇关于从JavaFX 8 update 20开始的非常酷的功能的博客&#xff0c;该功能使您的应用程序始终位于…

如何在内存序列化中使用Java深克隆对象

在我以前的文章中&#xff0c;我解释了深度克隆和浅层克隆之间的区别 &#xff0c; 以及复制构造函数和防御性复制方法比默认的Java克隆更好。 使用复制构造函数和防御性复制方法进行的Java对象克隆当然具有某些优势&#xff0c;但是我们必须显式编写一些代码才能在所有这些方…

复制网页内容

问题背景&#xff1a; 当网页复制东西时&#xff0c;可能因为某些原因导致无法复制。可以用以下方法解决 解决方法&#xff1a; 1. 按下F12&#xff0c;出现以下内容 2. 依次点击右上角三个点&#xff0c;弹出界面后点击shortcuts 3. 选择首选项后&#xff0c;选中Disable …

插入时间信息

问题描述 在进行文本编辑的时候&#xff0c;往往需要记录当天日期。而Typora等软件没有及时插入时间的快捷方式。 方法 搜狗收入法提供快速记录时间的方式 1. 在中文输入法模式中输入rq&#xff08;汉语拼音日期的首字母&#xff09;&#xff0c;选项卡自动显示今日日期,可…

activemq网络桥接_ActiveMQ –经纪人网络解释–第4部分

activemq网络桥接在前面的第3部分中 &#xff0c;我们已经看到ActiveMQ如何帮助将远程使用者与本地使用者区分开来&#xff0c;这有助于确定从消息生产者到使用者的较短路径。 在第4部分中&#xff0c;我们将研究如何在远程代理上负载均衡并发使用者。 让我们考虑一些高级配置…

sublime 添加注释模块

问题背景&#xff1a; 规范的程序需要对函数进行注释&#xff0c;常用的开发工具如IDEA、VS Code都对注释模板有很好的支持。本博客介绍Sublime下支持模块注释功能的设置。 一 安装 一、安装方法 1.安装docblocker插件 mac CmdShiftP -> Install Package -> docblock…

只读副本和Spring Data第3部分:配置两个实体管理器

我们之前的设置可以正常工作。 我们现在要做的是进一步发展&#xff0c;并配置两个单独的实体管理器&#xff0c;而不会影响我们之前实现的功能。 第一步是将默认的实体管理器配置设置为主要配置。 这是第一步 package com.gkatzioura.springdatareadreplica.config; import…

Win+E快速打开我的电脑方式设置方式

W10运用快捷键WinE快速打开我的电脑设置方式

JMetro版本11.6.5和8.6.5发布

再一次问好。 设置了SDK中所有JavaFX控件的样式以及其他一些不存在的样式以及其他库中的其他样式。 后续版本将涉及调整JMetro现有样式或从第三方库的其他控件添加其他样式。 此版本就是这种情况。 这是新功能&#xff1a; 3种新的控件样式&#xff1b; 调整JMetro现有样式&a…

Chrome浏览器的便捷使用方式

截取转载于B站视频【全套教程】高效玩转Chrome浏览器&#xff0c;丰富你的上网体验_哔哩哔哩_bilibili中的脑图文件&#xff0c;便于之后的熟悉使用。 脑图链接 https://naotu.baidu.com/file/5a5332eee10dd903cc084d49189cd2behttps://naotu.baidu.com/file/5a5332eee10dd90…

Sublime查看已经安装的插件

蓝色框图内显示已经安装的插件

activemq网络桥接_ActiveMQ –经纪人网络解释–第3部分

activemq网络桥接现在&#xff0c;我们已经在本博客系列的第1部分和第2 部分中了解了ActiveMQ网络连接器的基础&#xff0c;在第3部分中&#xff0c;我们将研究ActiveMQ如何平衡连接到代理网络的使用者。 介绍 当可以无序处理队列中的消息时通常使用并发使用者&#xff0c;通常…

Word样式的导入与导出

1 样式的介绍 样式&#xff0c;也就是Word中各级标题的格式。合理的设置样式模板&#xff0c;可以帮助更方便的进行文本编辑。 2 样式的导入 具体情形为将“文档标准模板.dotm”的内容应用于“新建Microsoft Word文档”。 按照图示进行操作 【 如果应用模板为文件内的样式…

word将一个文档的样式导入到另一个文档

一、背景 在word中编辑文档时&#xff0c;经常需要定义一个样式给特定格式的文本使用&#xff0c;如标题1&#xff0c;标题2等&#xff0c;而有时需要在一个新文档A中使用一个旧文档B中定义好的样式。 二、操作步骤 1、打开旧文档B&#xff0c;选择上方标签栏的"样式&quo…

Spring Boot应用程序浪费了内存

内存是当今世界上被广泛浪费的资源之一。 由于编程效率低下&#xff0c;令人吃惊的&#xff08;有时是“令人震惊的”&#xff09;内存浪费被浪费了。 我们看到这种模式在多个企业应用程序中重复出现。 为了证明这种情况&#xff0c;我们进行了一项小型研究。 我们分析了著名的…

Win10灵活使用快速访问

I 快速访问视图 位置在winE 左侧窗口&#xff0c;点击可快速到达某个特定的文件夹。作用类似于快捷方式&#xff0c;操作简单。 II 关闭自动添加 默认是显示经常使用的文件夹。这使得窗口内文件夹较乱。 通过以下设置&#xff0c;关闭自动显示 1. 2.把框内√去掉 III 固定文…

activemq网络桥接_ActiveMQ –经纪人网络解释–第2部分

activemq网络桥接在此博客中&#xff0c;我们将看到双工网络连接器如何工作。 在上一部分中&#xff0c;我们从broker-1和broker-2创建了一个网络连接器。 我们能够看到&#xff0c;当代理2上有一个使用者使用队列“ foo.bar”时&#xff0c;代理1上的队列“ foo.bar”的消息如…

Apache Lucene中的并发查询执行

Apache Lucene是一个出色的并发纯Java搜索引擎&#xff0c;如果您愿意&#xff0c;它可以轻松地使服务器上的可用CPU或IO资源饱和。 “典型” Lucene应用程序的并发模型在搜索时每个查询一个线程&#xff0c;但是您知道Lucene还可以使用多个线程同时执行一个查询以大大减少最慢…