【CSDN 编者按】这篇文章介绍了编写整洁的 Java 代码的一些原则和方法,包括遵循标准的项目结构、遵循命名规范、提高代码可读性、使用代码分析工具、编写有意义的注释和文档、保持一致和正确的代码格式、避免过多参数、编写单元测试、SOLID 原则、KISS 和 DRY 原则等。文章还给出了一些相关的链接和资源,以及作者的个人经验和建议。
原文链接:https://digma.ai/blog/clean-code-java/
未经允许,禁止转载!
就算是质量欠佳的代码,如果能够正常运行,问题或许不大。然而,如果代码不整洁,这就可能给整个开发团队带来困扰—— Uncle Bob。
经过数年科技行业的磨练,特别是在软件开发领域,我深刻体会到了这样一个现实:我绝大多数时间都与不同团队紧密合作,审查他们编写的代码。这些年与各种开发者合作的经验从本质上增进了我对整洁代码的理解和认知。
“实际上,我们阅读代码的时间远超编写代码的时间,这比例甚至超过 10 比 1。我们在致力于编写新代码的过程中,会不断阅读旧的代码。……[因此,] 要使代码易于编写,首先就要使其易于阅读。” ——摘自《代码整洁之道》 (Uncle Bob)。
无论你是资深的软件开发人员还是新入行者,我相信你都会理解学习和继承新代码库所需付出的艰辛和努力。你需要去理解这个代码库的代码结构、功能、编程语言、使用的库、框架和其他技术。
当你面对一段陌生的代码,或者是你自己很久以前写的代码,你可能会感到有些难以理解。无论你是想要修复错误、增强功能、提升性能,还是加入一个正在进行的项目,代码的整洁程度都将决定你需要投入的时间和精力。
按照整洁的 Java 代码原则编写的代码可以为你节省大量的时间和减少挫败感。相反,如果你正在处理混乱的代码,可能需要花费大量的时间去理解其逻辑、解读无注释的部分以及弄明白那些命名不清的变量。
整洁的代码意味着直观、易读、可测试和便于理解的代码。它的特点还包括遵循良好的编程规范和最佳实践,提高代码的表达力、简洁度、组织性和可维护性。此外,整洁的代码还应避免 bug 、无用的复杂性、代码异味和重复代码的问题。
大家称呼 Robert C. Martin 为 Uncle Bob,他是整洁代码主题的权威。无论程序员的经验如何,都可以从他关于代码整洁的书籍、文章和讲座中受益。
他在《代码整洁之道》书中写到:
*“虽然糟糕的代码能运行,如果代码不整洁,可能会导致开发团队效率低下。每年,由于代码质量差而损失的时间和资源是巨大的。然而,这种情况是可以避免的。”
编写整洁的 Java 代码的重要性毋庸置疑。以下是整洁代码带来的一些直接好处:
可维护性 - 整洁的代码便于维护和更新。
调试 - 整洁的代码减少错误,便于隔离和修复问题。
可扩展性 - 整洁的代码具有良好的模块化、可复用性,能更好地适应未来变化。
协作 - 整洁的代码增进团队成员之间对代码的理解。
文档 - 整洁的代码本身就足够清晰,降低了额外注释的需求。
效率 - 通过消除重复和无用的复杂性,整洁的代码能够提高性能。
可读性 - 整洁的代码的阅读性强,有助于降低混淆,增强可维护性。
Java 作为一门广受欢迎的编程语言,具有成熟的特性。许多旧版的 Java 代码库 至今仍在运行重要的商业软件和基础架构,这些项目始于十多年前,仍服务于大量用户。
鉴于 Java 代码库的长寿的特性,编写易于后续开发人员维护的整洁 Java 代码显得至关重要。下文列举了一些有助于编写整洁 Java 代码的最佳实践。
项目结构涉及如何在项目中组织各类组件,包括 Java 源文件、测试文件、文档文件、构建文件和配置文件。清晰的项目结构能使代码库更易理解、导航和修改。反之,混乱的项目结构可能会在处理大型项目时造成混淆。
虽然 Java 不强制特定的项目结构,但如 Maven 这样的构建工具为你提供了推荐的项目结构。
src
├── main
│ ├── java 应用/库源码
│ ├── resources 应用/库资源
│ ├── filters 资源过滤文件
│ └── webapp Web 应用源码
│
└── test
├── java 测试源码
├── resources 测试资源
└── filters 测试资源过滤文件
Java 命名规范由一系列规则组成,为 Java 开发人员命名变量、包、类和方法提供指导。Java 语言规范包括了这些命名规则。合理的命名能提升代码的可读性、一致性和可维护性。
Java 命名规范主要包括:
类和接口名以名词形式,首字母大写。
方法名以动词形式。
变量名需简短且有意义。
包名全小写。
常量名全部大写。
package com.example.project;
public class Person {
private String firstName;
private String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFullName() {
return firstName + " " + lastName;
}
public static final int MAX_AGE = 100;
public boolean hasValidName() {
return firstName != && lastName != ;
}
}
更多关于 Java 命名规范的信息,请参阅命名规范。
3. 优先考虑可读性,而非可重用性
虽然可重用性在软件开发中备受推崇,并且可以减少开发和维护时间,但当我们处理不熟悉的代码库时,也可能会引发一些潜在问题。在大型应用程序中,可重用性有时会牺牲可读性、可用性和可维护性,特别是在设计不当的情况下。随着代码逻辑流程变得难以理解,可重用性可能会影响代码的可读性。
不易理解的代码会增加调试难度和维护成本,特别是当试图吸引新开发人员加入项目时,这可能成为一项挑战。因此,在开发软件过程中,请确保可读性始终处于首要位置,不要盲目追求可重用性。
静态与动态代码分析工具各具优势,共同助力 Java 代码的质量提升。静态分析工具用于审查源代码,确保编码标准的一致遵循,能够在开发阶段就识别出潜在的漏洞和错误。
相对而言,动态分析则聚焦运行时应用程序的表现。它可以评估应用程序的性能、行为和功能,识别运行时的错误、内存泄漏及资源消耗,从而降低在生产环境中出现问题的风险。Digma 是一款出色的运行时代码检查工具,它可以帮助开发人员迅速定位风险代码、潜在错误和复杂代码库中的瓶颈。Digma 通过 OpenTelemetry 收集追踪、日志和指标等数据,并对其进行分析,以提供关于代码的深入洞察。它能识别诸如回归、异常、代码异味等模式,从而使开发人员能够确保更高质量的 Java 代码进入生产环境。
许多开发人员在软件开发初期,包括我自己,常常会过度使用注释。不适当的注释通常暗示代码编写的不佳。
在编写整洁的 Java 代码过程中,注释和文档的合理运用极为重要。虽然理想的代码应具备自我解释的特质,有时复杂逻辑却无法避免。然而,通过策略性地在代码中加入注释,可以解释某些部分背后不太直观的逻辑。
在 Java 中,开发人员常用两种类型的注释:文档注释和实现注释。前者面向代码库的使用者,后者则面向开发者。
/**
* 代表用于管理用户资源的 RESTful 控制器类。
* 提供了创建、检索、更新和删除用户的相关端点。
*/
public class UserController {
/**
* 通过 ID 检索用户。
*
* @param id 指定用户的 ID。
* @return 对应 ID 的用户。
*/
public ResponseEntity<User> getUserById( Long id) {
// 实现部分已省略以保持简洁
}
/**
* 创建新用户。
*
* @param user 待创建的用户对象。
* @return 新创建的用户。
*/
public ResponseEntity<User> createUser( User user) {
// 这里是实现部分
}
// 代码的其余部分
代码格式化在个人项目中或处理可能永远不会由他人维护的代码时,可能显得不那么重要。但在团队环境中,保持一致的代码格式化和风格则显得尤为关键。
要在团队中编写整洁的 Java 代码,确保团队和代码库中格式化和编码风格的一致性非常重要。空白和缩进是实现一致编码风格的关键因素。
合适的空白使用,如在运算符、逗号及控制语句周围,可增强代码的可读性。例如,您可以通过空白将代码划分为逻辑分组,从而提高可读性和视觉效果。
缩进是指在循环、方法和控制结构中使用制表符或空格。虽然 Java 没有强制的缩进规范,但选择并坚持使用流行的约定是明智的做法。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
// 其余代码部分
// ...
}
虽然参数在方法调用中非常重要,但应避免在一个方法中使用过多参数,因为过多的参数数量可能暗示方法处理多于一个关注点,从而违反单一职责原则。
参数过多会降低代码可读性,因为参数的类型和意义可能难以跟踪。为了编写整洁的 Java 代码,您应该限制方法参数的数量,并考虑使用对象或数据结构来替换单个参数或将相关参数组织到对象中。
以下是一个具有过多方法参数的 Java 方法示例:
public void processOrder(String customerName, String shippingAddress, String billingAddress,
String productName, int quantity, double price, boolean isExpressShipping) {
// 方法实现
}
下面是通过将相关参数组合到对象中以提高可读性的重构示例:
public class Order {
private String customerName;
private String shippingAddress;
private String billingAddress;
private String productName;
private int quantity;
private double price;
private boolean isExpressShipping;
// 构造器、访问器和修改器
// 与订单相关的其他方法
}
public void processOrder(Order order) {
// 方法实现
}
在软件开发领域,单元测试和测试驱动开发(TDD)是不可或缺的实践手段。单元测试的作用是对各个函数、方法和类的功能进行验证,保证它们能独立完成任务。而 TDD 则是一种优先编写测试再进行开发的方法。
通过采用单元测试和 TDD 方法,您能更加专注于编写规范、简洁的 Java 代码。单元测试可以帮助您及时验证代码的正确性,快速发现潜在错误,并促使您编写更模块化的代码结构。TDD 方法将为您提供及时的反馈,从而提高您编写可靠且易维护代码的信心。
来源:Twitter
9. SOLID 原则
SOLID 原则是由 Robert C. Martin(Uncle Bob)所提出,对于所有开发人员来说都非常重要,它有助于编写清晰、可维护和可扩展的代码。
以下将阐述 SOLID 原则如何引导您编写高质量的 Java 代码:
单一职责原则(Single Responsibility Principle,SRP):按照此原则,一个类只应担负一项职责,这有助于保证代码的简洁、可读性和维护性。
开放封闭原则(Open/Closed Principle,OCP):该原则要求类应对扩展开放,对修改封闭,除非进行错误修复。这使得您可以在不破坏现有功能的前提下添加新特性。在 Java 中,借助接口或抽象类能实现现有类的功能扩展。
里氏替换原则(Liskov Substitution Principle,LSP):此原则确保您能够在不影响程序正常运行的情况下,灵活地将超类与其各个子类进行互换。遵循这一原则有助于正确使用继承,编写结构松耦合的优雅 Java 代码。
接口隔离原则(Interface Segregation Principle):此原则鼓励选择较小、更具针对性的接口,而非庞大、泛化的接口。这使得您能够编写更加模块化和简洁的 Java 代码,确保实现类仅专注于与其相关的功能。
依赖倒置原则(Dependency Inversion Principle,DIP):依赖倒置原则强调降低组件间的紧耦合,推崇依赖于抽象而非具体实现。遵循此原则,您可以通过控制反转(IoC)和依赖注入实现结构清晰的 Java 代码。
KISS 和 DRY 是编程中的基础原则,对于编写精炼的 Java 代码至关重要。DRY 原则主张开发者确保系统中代码不重复,以此提升代码的可维护性,并使查找和修复错误更为高效。
KISS 原则(Keep It Simple, Stupid)则倡导在软件设计和开发过程中保持简洁明了。遵循此原则,你可以消除代码中的不必要复杂性,从而选择更易理解的编码方式。
KISS 原则(Don't Repeat Yourself)有助于增强代码的可维护性和可读性,从而提升团队协作效率,也使新成员更容易融入项目。
Java 的标准源文件包括运行任何 Java 程序所需的关键组成部分。为了保持代码的可读性,你应当遵循一致的源文件结构。虽然没有普遍适用的源文件结构,但存在一些广受推崇的风格指南。
一般来说,Java 的源文件结构应该从包声明开始,接着是静态和非静态的导入声明,最后定义一个主要的顶级类。
// 类变量
private static int count;
private String name;
// 实例变量
private int age;
private List<String> hobbies;
// 构造函数
public MyClass() {
// 构造函数实现
}
public MyClass(String name, int age) {
// 构造函数实现
}
// 方法
public void setName(String name) {
// 方法实现
}
public String getName() {
// 方法实现
}
public void addHobby(String hobby) {
// 方法实现
}
// 其他方法
}
// 额外的类(如果有)
class MyStaticClass {
// 类实现
}
硬编码是将值直接嵌入到程序源代码的一种做法,不使用变量表示。对硬编码的值进行更改必须修改程序源代码,这样的做法极大地限制了代码的重用性和可测试性,并可能引发程序错误和代码重复问题。
为了增强代码的重用性、可测试性和可维护性,应该避免在程序源代码中使用硬编码值。这些都是整洁 Java 代码的核心特性。您可以通过使用抽象概念,例如常量变量或枚举,来替换硬编码的值。
以下是一个包含硬编码值的 Java 程序示例:
public class HelloWorldController {
public String sayHello() {
return "Hello, World!";
}
public String getUser() {
// 硬编码值
String username = "John";
int age = 30;
return "Username: " + username + ", Age: " + age;
}
// 其他控制器方法
}
编写整洁的 Java 代码是构建高质量软件的基础。
在这篇文章中,我们探讨了一些有助于编写整洁 Java 代码的主要和常见实践。然而,值得强调的是,还存在许多其他关键因素,包括团队文化、可用工具和团队目标。遵循这些原则,你可以构建出可读、可测试、可扩展和模块化的代码。
整洁代码是什么?
整洁代码指的是遵循最佳实践和编码规范所编写的、具有良好可读性和可维护性的代码。它不仅易于原作者理解、修改和扩展,同时也方便后续维护的开发人员。
为何编写整洁代码很重要?
编写整洁的代码可以提高代码可读性,增进团队协作,降低错误发生的概率,并且使得代码维护变得更为便捷。
有哪些工具能够帮助编写整洁的 Java 代码?
有许多辅助工具可供选择,用于编写整洁的 Java 代码,包括静态代码分析工具如 SonarQube、FindBugs 和 Digma 等,以及某些集成开发环境(IDE),例如 IntelliJ 和 Eclipse。
我可以从哪些资源中学习到更多关于编写整洁的 Java 代码的知识?
有许多博客和在线教程提供相关信息,例如 Baeldung 网站。此外,还有一些值得推荐的书籍,如 Robert C. Martin 的《代码整洁之道》和 Joshua Bloch 的《Effective Java》。
你认为编写整洁代码重要吗?你还有哪些编写整洁代码的经验?
粉丝福利: