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

程序员 rs编码

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

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

本文中的所有源代码都是开源的,可以在以下位置获得
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 。 这是解决问题的一种解决方案:

势在必行

声明式解决方案

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

势在必行

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

分析

SonarQube提供以下分析:

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

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

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

实施REST接口

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

程序员 rs编码

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

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

相关文章

对象包装器与自动(拆箱)装箱+参数数量可变的方法+枚举类

【0】README 0.1&#xff09; 本文描述源代码均 转自 core java volume 1&#xff0c; 旨在理解 自动拆箱&#xff08;装箱&#xff09;、printf的参数数量可变 以及 枚举类的详细说明&#xff1b; 0.2&#xff09; 源代码&#xff1a; https://github.com/pacosonTang/core…

go 监测tcp 连接断开_TCP三次握手和四次挥手以及11种状态

三次握手置位概念&#xff1a;根据TCP的包头字段&#xff0c;存在3个重要的标识ACK、SYN、FINACK&#xff1a;表示验证字段 SYN&#xff1a;位数置1&#xff0c;表示建立TCP连接 FIN&#xff1a;位数置1&#xff0c;表示断开TCP连接三次握手过程说明&#xff1a;1.由客户端发送…

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

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

java反射机制+继承设计技巧

【0】README 0.1&#xff09; 本文描述源代码均 转自 core java volume 1&#xff0c; 旨在理解 java反射机制 &#xff1b;最后还顺带提出了 继承设计的技巧&#xff1b; 【1】反射相关 1&#xff09;反射定义&#xff1a;能够分析类能力的程序称为反射&#xff1b; 2&…

60秒计时器的仿真电路_基于伏秒平衡的同步整流方案探讨

为了提高电源的效率和功率密度&#xff0c;尤其是低输出电压的应用场合&#xff0c;同步整流是不可或缺的。图1-1 反激输出二极管损耗比如上图的反激电源如果输出二极管 Vf0.7V&#xff0c;输出电压 Vout3V 则效率不会高于3/(30.7)81%。为了提升效率一般会选用低导通压降的肖特…

利用反射机制创建新类的两种方式及比较

【0】README 0.1&#xff09; 本文描述源代码均 转自 http://blog.csdn.net/fenglibing/article/details/4531033 &#xff0c; 旨在深入理解 如何利用反射机制创建类实例&#xff1b; 0.2&#xff09; 转载的源代码&#xff0c;参见 https://github.com/pacosonTang/core-ja…

如何设计高效测试用例_高效的企业测试-单元和用例测试(2/6)

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

php mysql study_PHPstudy升级mysql数据库

首先查看phpstudy的mysql版本&#xff1a;方法一 使用mysql的version函数&#xff1a;mysql> selectversion();方法二 status命令mysql> status&#xff1b;方法三 直接在cmd下输入命令查看mysql -vmysql --help下面开始升级数据库1、备份好自己的数据库2、清空phpstudy…

selenium 等待_Selenium等待:内隐,外显,流利和睡眠

selenium 等待Selenium等待页面加载在Selenium脚本中起着重要的作用。 它们有助于使它们不易剥落&#xff0c;更可靠。 Selenium提供多次等待&#xff0c;以根据某些条件在脚本执行中提供足够的等待或暂停。 从而确保您在使用Selenium执行自动化测试时不会导致脚本失败。 在本教…

java接口概述

【0】README 0.1&#xff09; 本文描述源代码均 转自 core java volume 1&#xff0c; 旨在理解 java 接口概念 &#xff1b; 0.2&#xff09;接口技术&#xff1a; 这种技术主要用来描述类具有什么功能&#xff0c; 并不给出每个功能的具体实现&#xff1b; 一个类可以实现多…

通过aws部署推荐系统_通过AWS Elastic Beanstalk轻松进行Spring Boot部署

通过aws部署推荐系统朋友不允许朋友写用户身份验证。 厌倦了管理自己的用户&#xff1f; 立即尝试Okta的API和Java SDK。 数分钟之内即可在任何应用程序中对用户进行身份验证&#xff0c;管理和保护。 几乎所有应用程序都依赖于身份验证。 开发人员以及雇用他们的公司都想确认…

图论算法基础

【0】README 0.1&#xff09;本文总结于 数据结构与算法分析&#xff0c; 旨在复习数据结构中图论算法的基础知识&#xff1b; 【1】图论若干相关定义 1.1&#xff09;图G定义&#xff1a;一个图G&#xff08;V&#xff0c;E&#xff09;由顶点及集V 和 边集E组成&#xff0c…

mysql 表丢失_Mysql数据库备份 部分数据表丢失 Mysql table doesn't exist 解决

问题&#xff1a;直接拷贝data下的数据库数据进行备份&#xff0c;重装升级了数据库&#xff0c;直接复制备份数据到新的数据库data目录下&#xff0c;发现部分数据表不见了。原因分析&#xff1a;以表“Table”为例:如类型是MyISAM, 数据文件则以”Table.frm”&#xff0c;”T…

aws 删除ec2实例_如何在AWS EC2实例上部署Spring Boot应用程序

aws 删除ec2实例你好朋友&#xff0c; 在本教程中&#xff0c;我们将看到如何在AWS EC2实例上部署Spring Boot应用程序。 这是我们将要执行的步骤。 1.使用Spring Boot Initialiser创建一个Spring Boot项目。 2.创建一个休息端点&#xff0c;部署后我们可以访问 3.启动EC2…

jdbc操作mysql数据库_JDBC操作MySQL数据库(一)

连接MySQL数据库连接数据源有两种方式&#xff1a;1)通过DriverManager类2)通过DataSource接口及JNDI资源获得连接DriverManager类的路径为java.sql.DriverManager&#xff0c;它主要完成驱动程序的装载和建立新的数据库连接。其常用方法如下&#xff1a;* getConnection (Stri…

只读事务上下文_我可以/应该在事务上下文中使用并行流吗?

只读事务上下文介绍 长话短说&#xff0c;您不应在并行流中使用事务。 这是因为并行流中的每个线程都有其自己的名称&#xff0c;因此它确实参与了事务。 Streams API旨在在某些准则下正常工作。 实际上&#xff0c;为了受益于并行性&#xff0c;不允许每个操作更改共享对象的…

mysql多表查询详解_MySQL多表查询详解上

时光在不经意间&#xff0c;总是过得出奇的快。小暑已过&#xff0c;进入中暑&#xff0c;太阳更加热烈的绽放着ta的光芒&#xff0c;...在外面被太阳照顾的人们啊&#xff0c;你们都是勤劳与可爱的人啊。在房子里已各种姿势看我这篇这章的你&#xff0c;既然点了进来&#xff…

无权最短路径

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在理解 无权最短路径 的思想并用源代码加以实现&#xff1b; 【1】无权最短路径相关概念&#xff08;边的权值赋值为1&#xff09; 1.1&#xff09;概述&#xff1a;下…

java 键入_在Java中键入Safe SQL

java 键入字符串&#xff0c;字符串&#xff0c;字符串 无论您使用的是JPA &#xff0c; MyBatis还是Spring Data JDBC之类的框架&#xff0c;总会最终将SQL语句声明为Java String。 这种方法的问题在于&#xff0c;您必须为每个语句编写测试&#xff0c;以确保它甚至是有效SQ…

filter过滤后重新添加_Spring Boot 2.X(十):自定义注册 Servlet、Filter、Listener

前言在 Spring Boot 中已经移除了 web.xml 文件&#xff0c;如果需要注册添加 Servlet、Filter、Listener 为 Spring Bean&#xff0c;在 Spring Boot 中有两种方式&#xff1a;使用 Servlet 3.0 API 的注解 WebServlet、WebFilter、Listener 用来配置。Spring Boot JavaConfig…