在Java中清洁编码
最后修改:2020年12月31日
1.概述
在本教程中,我们将通过干净的编码原则。我们还将理解为什么清洁代码很重要,如何在Java中实现这一目标。此外,我们会看看是否有任何可用于帮助我们的工具。
2.什么是干净的代码?
所以,在我们进入干净代码的细节之前,让我们先理解干净代码是什么意思。老实说,这个问题没有一个好的答案。在编程中,一些关注点跨越并由此产生一般原则。但是,每一种编程语言和范式都有自己的一套细微之处,这就要求我们采用合适的实践。
宽广地,干净的代码可以总结为任何开发人员都可以轻松阅读和更改的代码。虽然这听起来似乎过于简化了这个概念,但我们将在本教程的后面部分看到它是如何构建的。在任何我们听到干净代码的地方,我们金宝搏官网188be可能会遇到一些Martin Fowler的参考。下面是他在其中一个地方对干净代码的描述:
任何傻瓜都可以编写计算机可以理解的代码。良好的程序员编写人类可以理解的代码。
3.我们为什么要关心干净的代码?金宝搏官网188be
编写干净的代码是一种个人习惯,也是一种技能。作为一名开发者,随着时间的推移,我们通过经验和知识成长。但是,我们必须问,我们为什么要投资开发干净的代码呢?我们知道其他人可能会发现我们的代码更容易阅读,但这就足够了吗?让我们来看看!
干净的编码原则有助于我们实现与我们打算生产的软件相关的许多理想的目标。让我们通过他们更好地了解:
- 可维护的代码库我们开发的任何软件都有生产周期,在此期间将需要更改和一般维护。干净代码可以帮助开发易于改变和维护的软件随着时间的推移。
- 更容易进行故障排除软件可能会由于各种内部或外部因素而表现出意想不到的行为。它可能经常需要修复和可用性方面的快速周转。用清晰的编码原则开发的软件是否更容易排除问题。
- 更快的onboarding软件在其生命周期中会有许多开发人员创建、更新和维护它,开发人员在不同的时间点加入。这需要更快地onboard,保持高效性高,干净的代码有助于实现这一目标。
4.清洁代码的特征
用干净的编码原则编写的代码库显示出几个使它们与众不同的特征。让我们来看看这些特征:
- 专注:一块应该编写代码来解决特定问题。它不应该做任何与解决给定问题无关的事情。这适用于代码库中的所有抽象级别,如方法、类、包或模块。
- 简单的:这是干净代码最重要也是最常被忽略的特性。该软件设计和实现必须尽可能简单,这可以帮助我们达到预期的结果。代码库中不断增加的复杂性使得它们容易出错,并且难以阅读和维护。
- 可测试干净的代码虽然简单,但必须解决手边的问题。它必须是直观且易于测试CodeBase,最好以自动化方式。这有助于建立代码库的基线行为,并使更改它更容易而不破坏任何东西。
这些是帮助我们实现上一节讨论的目标的帮助。与稍后的重构相比,开始使用这些特征开始发展是有益的。这导致软件生命周期的总体拥有成本较低。
5.在Java中清洁编码
现在我们经历了足够的背景,让我们看看我们如何在Java中纳入清洁的编码原则。Java提供了许多最佳实践,可以帮助我们编写清洁代码。我们将在不同的存储桶中缩小它们,并了解如何使用代码示例来编写清洁代码。
5.1。项目结构
虽然Java不强制任何项目结构,遵循一致的模式来组织源文件,测试,配置,数据和其他代码工件始终有用。Maven是一种流行的Java构建工具,规定了一个特定的项目结构。虽然我们可能不使用maven,但坚持惯例总是很好。
让我们看看Maven建议我们创建的一些文件夹:
- src / main / java:对于源文件
- SRC / Main / Resources:对于资源文件,如属性
- src /测试/ java:用于测试源文件
- src /测试/资源:用于测试资源文件,如属性
与此类似,有其他受欢迎的项目结构,如Bazel我们应该根据我们的需求和受众来选择一个。
5.2。命名约定
下列的命名约定可以在使我们的代码可读和因此可维护方面进行很长的路要走。Rod Johnson,春天的创造者,强调命名约定的重要性在春天:
“……如果你知道某个东西是做什么的,你就很有可能猜出它的Spring类或接口的名字……”
Java规定一套规则在Java中命名任何东西时都要坚持。一个格式良好的名称不仅有助于阅读代码,而且还传达了很多关于代码意图的信息。金宝搏官网188be让我们举几个例子:
- 类:从面向对象的概念来看,类是对象的蓝图,通常代表真实世界的对象。因此,使用名词来命名充分描述它们的类是有意义的:
公共课程客户{}
- 变量: Java中的变量捕获从类中创建的对象的状态。变量名应该清楚地描述变量的意图:
public class customerName {private String customerName;}
- 方法:Java中的方法始终是类的一部分,因此通常代表从类创建的对象的状态的动作。因此使用动词命名方法很有用:
public class customerName {private String customerName;public String getCustomerName() {return this.customerName;}}
虽然我们只讨论了如何在Java中命名标识符,但请注意还有其他的最佳实践,如驼峰式套管,为了可读性,我们应该观察这些最佳实践。还可以有更多与命名接口、枚举和常量相关的约定。
5.3。源文件结构
源文件可以包含不同的元素。java.编译器强制执行一些结构,大部分是流体。但是,遵守到源文件中的元素的特定顺序可以显着提高代码可读性。有多种流行的风格导游,以吸取灵感,就像一个人一样谷歌另一个春天。
让我们看看如何在源文件中典型的元素排序:
- 包装声明
- 进口陈述
- 所有静态进口
- 所有非静态导入
- 只有一个顶级阶层
- 类变量
- 实例变量
- 构造师
- 方法
除了上面,方法可以根据其功能或范围进行分组。没有一个好的会议,而这个想法应该是决定一次,然后始终如一。
让我们看看一份良好的源文件:
#/src/main/java/com/b金宝搏188体育aeldung/application/entity/customer.java包com.baeldung.application.entity;导入java.util.date;public class customerName {private String customerName;私人日期加入德国;公共客户(String CustomerName){this.Customername = CustomName;this.joiningdate =新日期();public string getCustomerName(){返回this.Customername;公共日期getJoiningDate(){返回它.Joindingdate;}}
5.4。空白
与大块文本相比,我们都知道更容易阅读和理解短段。在阅读代码时,它不是很困难。放置良好,一致的空白和空线可以增强代码的可读性。
这里的想法是在代码中引入逻辑分组,这有助于在试图通读时组织思维过程。这里没有单一的规则可以采用,只有一套通用的指导原则和保持可读性的内在意图:
- 在开始静态块、字段、构造函数和内部类之前有两个空行
- 多行方法签名后的一个空行
- 用一个空格分隔保留的关键字,如if、for、catch和开括号
- 单个空间分离保留关键字,如别的,从闭合括号中捕获
这里的列表并不穷,但应该让我们成为一个轴承朝向。
5.5。缩进
虽然非常微不足道,但几乎任何开发者都会担保这一事实缩进良好的代码更容易阅读和理解。Java中没有单一的代码缩进约定。这里的关键是采用流行的惯例或定义私有的惯例,然后在整个组织持续遵循它。
让我们看看一些重要的缩进标准:
- 一个典型的最佳实践是使用四个空格,一个缩进单位。请注意,一些指南建议使用标签代替空格。虽然这里没有绝对的最佳实践,但关键是保持一致性!
- 通常,在线长度应该有一个帽子,但由于较大的屏幕开发人员今天使用,这可以设置比传统80更高。
- 最后,由于许多表达式不适合单线,我们必须一致地打破它们:
- 逗号后打破方法调用
- 在运营商之前的打破表达
- 缩进包装线条以获得更好的可读性(我们在Baeldung喜欢两个空间)金宝搏188体育
让我们看看一个例子:
list customersids = customer.stream().map(客户 - > customer.getcustomerId()).collect(收集器.Tocollection(ArrayList :: New));
5.6。方法参数
参数对于方法按照规范工作是必不可少的。但是,一长串参数可能会使某些人难以阅读和理解代码。那么,我们应该在哪里划清界限呢?让我们来了解一下可能对我们有所帮助的最佳实践:
- 尝试限制方法接受的参数数量,三个参数可以是一个不错的选择
- 如果该方法需要比推荐的参数更多的参数,请考虑重构该方法,通常很长的参数列表也表明该方法可能做多种事情
- 我们可以考虑将参数绑定到定制类型中,但必须注意不要将不相关的参数转储到单一类型中
- 最后,虽然我们应该使用这个建议来判断代码的可读性,但我们不能对此过于迂腐金宝搏官网188be
让我们看看这个例子:
public boolean setCustomerAddress(String firstName, String lastName, String streetAddress, String city, zipCode, String state, String country, String phoneNumber){} //可以重构如下以增加可读性
5.7。硬编码
在代码中硬编码值通常会导致多种副作用。例如,它可以导致复制,这使得变化更加困难。如果值需要是动态的,通常会导致不希望的行为。在大多数情况下,硬编码的值可以通过以下方式之一进行重构:
- 考虑用Java中定义的常量或枚举替换
- 或者,替换在类级别或单独的类文件中定义的常量
- 如果可能的话,替换为可以从配置或环境中挑选的值
让我们看看一个例子:
私有int storeClosureDay = 7;//这个可以被重构来使用Java私有的常量int storeClosureDay = DayOfWeek.SUNDAY.getValue()
同样,在这方面也没有严格的指导方针。但是我们必须认识到这样一个事实:有些人以后需要阅读金宝搏官网188be和维护这些代码。我们应该选择一个适合我们的惯例,并且保持一致。金宝搏官网188be
5.8。代码评论
代码注释可阅读代码的益处以了解非琐碎的方面。同时,要注意不要在评论中包含明显的东西。这会使评论膨胀,使阅读相关部分变得困难。
Java允许两种评论:实现评论和文档评论。它们具有不同的目的和不同的格式。让我们更好地了解它们:
- 文档/ JavaDoc注释
- 这里的观众是代码库的用户
- 这里的细节通常与实现无关,更多地关注于规范
- 通常独立于代码库是有用的
- 实施/阻止评论
- 这里的观众是在Codebase上工作的开发人员
- 这里的细节是具体实现的
- 通常与代码库一起使用
那么,我们应该如何优化使用它们,使它们既有用又符合上下文呢?
- 注释应该只对代码进行补充,如果没有注释我们无法理解代码,也许我们需要重构它
- 我们应该很少使用块注释,可能描述非琐碎的设计决策
- 我们应该为大多数类,接口,公共和保护方法使用javadoc评论
- 所有评论都应该完整地形成适当的缩进以获得可读性
让我们看一下有意义的文档评论的示例:
/** *此方法旨在为客户添加一个新地址。*但是请注意,每个邮政编码只允许一个地址。因此,这将覆盖以前使用相同邮政编码的任何地址。* * @param address a address to be added for an existing customer */ /* *这个方法使用了equals *方法的自定义实现,以避免相同邮政编码的地址重复。*/ public addCustomerAddress(Address Address) {}
5.9。日志记录
任何曾经把手放在调试的生产代码上的任何人都在某个时间点逐渐纳入更多的日志。这在一般的开发和维护中,日志的重要性再怎么强调也不过分。
Java有很多库和框架,用于记录,包括SLF4J,回荡。虽然它们在CodeBase中进行了令人生畏的速度,但必须小心注销最佳实践。否则做的日志记录可以证明是维护噩梦,而不是任何帮助。让我们通过一些最佳实践:
- 避免过多的日志记录,考虑哪些信息可能对故障排除有帮助金宝搏官网188be
- 明智地选择日志级别,我们可能希望在生产环境中有选择地启用日志级别
- 在日志消息中使用上下文数据要非常清晰和描述性
- 使用外部工具来跟踪、聚合和过滤日志消息,以更快地进行分析
让我们看一下具有正确级别的描述性日志记录的示例:
logger.Info(String.Format(“已使用客户ID创建的新客户:%s”,ID));
6.这就是全部吗?
虽然上一节强调了几种代码格式约定,但这些不是我们应该知道和关心的唯一约定。金宝搏官网188be可读和可维护的代码可以从长期积累的大量其他最佳实践中获益。
随着时间的推移,我们可能会遇到它们作为有趣的首字母缩写。他们基本上捕获了学习作为一个可以帮助我们编写更好代码的单一或一组原则。但是,请注意,我们不应该仅仅因为它们的存在就遵循它们。大多数时候,它们提供的好处与代码库的大小和复杂性成正比。我们必须在采用任何原则之前访问我们的代码库。更重要的是,我们必须与他们保持一致。
6.1。坚硬的
SOLID是一个从它阐述的五个原则用于编写可理解和可维护的软件:
- 单一责任原则: 每一个我们定义的接口、类或方法应该有明确定义的目标。从本质上讲,它应该理想地做一件事,做得好。这有效地导致较小的方法和类别也可测试。
- 开放式原则我们所写的代码应该是理想的对扩展开放,但对修改关闭。这实际上意味着一个类应该以一种不需要修改它的方式编写。然而,它应该允许通过继承或组合进行更改。
- 利斯科夫替代原则这一原则所阐明的是每个子类或派生类都应替换为他们的父级或基类。这有助于减少代码库中的耦合,从而提高可重用性。
- 接口隔离原则实现接口是为类提供特定行为的一种方式。然而,一个类必须不需要实现它不需要的方法。这需要我们定义更小、更集中的接口。
- 依赖性倒置原则:根据这个原则,类应该只依赖于抽象,而不是它们的具体实现。这实际上意味着一个类不应该负责为其依赖项创建实例。相反,这些依赖应该被注入到类中。
6.2。干和吻
DRY代表“Don's Repeat Yourself”。这个原则指出在软件中不应重复一段代码。这一原则背后的基本原理是减少重复和增加可重用性。但是,请注意,我们在采用这一方法时应该谨慎,因为它过于字面化。一些重复实际上可以提高代码的可读性和可维护性。
Kiss代表“保持简单,愚蠢”。这个原则指出我们应该尽量保持代码尽可能简单。这使得容易理解和维护随着时间的推移。在前面提到的一些原则之后,如果我们保留我们的课程和方法专注和小,这将导致更简单的代码。
6.3。TDD.
TDD代表“测试驱动开发”。这是一个要求我们这样做的编程实践只有在自动化测试失败时才编写任何代码。因此,我们已经从自动测试的设计开发开始。在Java中,有几个框架可以像JUnit和Testng一样编写自动单元测试。
这种做法的好处是巨大的。这导致始终按预期工作的软件。正如我们始终从测试开始,我们逐步添加小块中的工作代码。此外,如果新的或任何旧测试失败,我们只添加代码。这意味着它也会导致可重用性。
7.工具的帮助
写清洁代码不仅仅是一个原则和实践的问题,但这是个人习惯。我们倾向于在学习和适应时变得更好的开发人员。然而,为了保持一支大型团队的一致性,我们还练习了一些执法。代码评论一直是一个很好的工具,以保持一致性并通过建设性的反馈帮助开发者成长。
然而,我们不必在代码评审期间手动验证所有这些原则和最佳实践。弗雷迪Guime从Java OffHeap讨论了自动化金宝搏官网188be一些质量检查的价值,以便始终以特定的代码质量阈值结束。
有Java生态系统中可用的几个工具,至少一些责任远离代码审阅者。让我们看看其中一些工具是什么:
- 代码格式:大多数流行的Java代码编辑器,包括Eclipse和Intellij,允许自动代码格式化。我们可以使用默认格式规则,自定义它们,或用自定义格式规则替换它们。这需要很多结构代码约定。
- 静态分析工具:有几个用于Java的静态代码分析工具,包括索纳里克,校验型,PMD和SpotBugs。它们有一组丰富的规则,可以按原样使用,也可以为特定的项目定制。它们在检测大量代码(如违反命名约定和资源泄漏)方面非常出色。
结论
在本教程中,我们已经了解了干净代码所展示的干净编码原则和特征的重要性。我们看到了如何在实践中采用其中的一些原则,这些原则是用Java开发的。我们还讨论了其他有助于保持代码可读性和可维护性的最佳实践。最后,我们讨论了一些可以帮助我们完成这项工作的工具。
总之,需要注意的是,所有这些原则和实践都是为了让我们的代码更简洁。这是一个更加主观的术语,因此必须根据上下文进行评估。
虽然有许多可用于采用的规则,但我们必须意识到我们的成熟,文化和要求。我们可能必须自定义或此事,共同设计一套新的规则。但是,无论如何,案例可能,在整个组织中保持一致,以获得福利。