欢迎来到啾啾的博客🐱,一个致力于构建完善的Java程序员知识体系的博客📚,记录学习的点滴,分享工作的思考、实用的技巧,偶尔分享一些杂谈💬。
欢迎评论交流,感谢您的阅读😄。
目录
[1. 方法名的结构](#1. 方法名的结构)
[2. 参数与返回值的隐含](#2. 参数与返回值的隐含)
[3. 避免缩写](#3. 避免缩写)
[4. 逻辑与副作用的体现](#4. 逻辑与副作用的体现)
[5. 条件判断方法](#5. 条件判断方法)
[1. 利用上下文环境简化名称](#1. 利用上下文环境简化名称)
[2. 使用领域术语或缩写](#2. 使用领域术语或缩写)
[3. 拆分复杂逻辑为小模块](#3. 拆分复杂逻辑为小模块)
[4. 使用组合命名结构](#4. 使用组合命名结构)
[5. 保留核心信息,舍弃冗余修饰词](#5. 保留核心信息,舍弃冗余修饰词)
引言
从在大学机房里敲下Hello World那刻起,我踏入了编程的世界。
工作以来,不同的项目、不同的团队都带来有不同的编程规范,关于规范的注意事项是在太多太多,最后留在脑海里的只余下"可读性、可拓展性、设计原则",让具体阐释一时间也说不出个所以然来。
哦,脑海里还余下了阅读、改动那些没遵守规范的代码时头疼的感觉。
为了消除这"头疼的感觉",今天便系统整理一下代码规范,什么样的规范才是好的规范呢?
良好的命名规范能减轻工作负担。 ------ 啾啾
先从命名开始。
命名------提炼含义减少注释
好的命名再怎么强调也不为过。
我们可能见过一些程序员,他们会为代码写上一大堆注释来说明这个方法做了什么。
可是事实上,"注释往往是最短命的代码",注释本身有着不确定的一致性。
正确的做法是,提炼含义,使用描述明确的代码类、函数方法命名,好的代码注释应该解释"为什么",而非"是什么"。(代码本身应该尽量自解释)
下面以一些Java基础类为例。
类名命名
先看一些Java源码示例。
类名 | 含义解析 |
---|---|
ArrayList |
基于数组 (Array)的List实现 |
LinkedList |
基于链表 (Linked)的List实现 |
TreeSet |
基于红黑树 (Tree结构)的Set实现 |
SimpleDateFormat |
简单的日期格式化工具(Simple 修饰核心功能DateFormat ) |
FileInputStream |
基于文件 (File)的输入流(InputStream)实现 |
类的命名上,要含义明确得体现实现方式或功能,避免模糊命名。
还有一种情况,即项目结构是Service、DAO、BO、VO这些,命名需要使用后缀体现层级关系。
类名 | 含义解析 |
---|---|
UserServiceImpl |
实现UserService 接口的业务逻辑类 |
OrderDAO |
数据访问层(DAO)的订单操作类 |
ProductBO |
业务对象(Business Object),封装业务逻辑 |
CartVO |
视图对象(View Object),用于前端展示的数据模型 |
接口与实现类的命名
接口/抽象类 | 实现类 | 含义解析 |
---|---|---|
List |
ArrayList , LinkedList |
实现类通过后缀明确具体实现方式 |
Map |
HashMap , TreeMap , LinkedHashMap |
实现类通过后缀明确具体实现方式 |
Collection |
ArrayList , HashSet , PriorityQueue |
通过具体实现类名体现数据结构 |
方法命名的最佳实践
方法命名的核心原则是意图明确、参数隐含、无歧义。以下是具体示例和规则:
1. 方法名的结构
- 动词 + 对象/动作 :方法名以动词开头,描述操作内容。
- ✅
addElement()
(添加元素) - ✅
calculateTotalPrice()
(计算总价) - ✅
saveToFile()
(保存到文件) - ❌
process()
(模糊,应具体化为processPayment()
或processRequest()
)
- ✅
2. 参数与返回值的隐含
- 通过方法名暗示参数和返回值的类型:
- ✅
findUserById(String id)
(隐含返回User
对象) - ✅
getMaxValue(int[] numbers)
(隐含返回最大值) - ❌
getSomething()
(不明确返回值类型或用途)
- ✅
3. 避免缩写
- ❌ 缩写 :
calc()
(不明确) - ✅ 完整命名 :
calculate()
(清晰)
4. 逻辑与副作用的体现
- 副作用 :若方法有副作用(如修改状态),应在名称中体现:
- ✅
updateCache()
(明确修改缓存) - ✅
resetSettings()
(明确重置设置) - ❌
doAction()
(不明确副作用)
- ✅
5. 条件判断方法
- 布尔方法以
is
、has
、can
开头:- ✅
isConnected()
(判断是否连接) - ✅
hasPermission()
(判断是否有权限) - ✅
canExecute()
(判断是否可执行)
- ✅
长命名处理------实战答疑
在命名时,偶尔会有业务复杂命名难以提炼的情况。
处理方法
可以通过以下策略在保持清晰性和可维护性的同时缩短名称:
1. 利用上下文环境简化名称
-
类/模块上下文:在类或模块名中已体现的业务范围,方法名/变量名可省略重复信息。
- 示例:
java
// 类名已包含 "Transaction",方法名无需重复
public class TransactionProcessor {
private void validateTransaction() { ... } // 可简化为 validate()
private void calculateTotal() { ... } // 上下文已明确是交易总金额
}
-
参数/返回值隐含:通过参数名或返回值类型暗示功能,减少名称冗余。
- 示例:
java
// 参数已明确是 "User",方法名无需重复
public void sendVerificationEmailToUser(User user) { ... }
// 可简化为
public void sendVerificationEmail(User user) { ... }
2. 使用领域术语或缩写
-
领域术语:使用业务领域中的通用术语,减少冗余描述。
- 示例:
java
// 业务术语 "SubscriptionTier" 可直接使用
public double calculateDiscount(SubscriptionTier tier) { ... }
-
合理缩写:
- 通用缩写 :如
Tx
(Transaction)、Svc
(Service)、Mgr
(Manager)。 - 团队约定 :确保团队对缩写达成一致(如
User
代替UserAccount
)。 - 示例:
- 通用缩写 :如
java
// 原名称:calculateCustomerDiscountBasedOnSubscriptionTier
// 简化后:calculateDiscountByTier(假设Tier是业务术语)
public double calculateDiscountByTier(SubscriptionTier tier) { ... }
3. 拆分复杂逻辑为小模块
-
方法拆分:将长方法拆分为多个职责单一的小方法,每个方法命名清晰。
- 示例:
java
// 原长方法:processOrderWithPaymentAndDelivery()
// 拆分后:
public void processOrder(Order order) {
validateOrder(order);
applyPayment(order);
scheduleDelivery(order);
}
-
类拆分:将复杂类拆分为多个子类或辅助类,通过组合提升可读性。
- 示例:
java
// 原类:OrderProcessorWithPaymentAndDelivery
// 拆分后:
public class OrderProcessor {
private final PaymentProcessor paymentProcessor;
private final DeliveryScheduler deliveryScheduler;
// ...
}
4. 使用组合命名结构
-
Builder模式:通过链式调用或构建器减少参数名称的冗余。
- 示例:
java
// 原名称:createOrderWithCustomerAndItemsAndDiscount()
// 使用Builder模式:
Order order = new Order.Builder()
.setCustomer(customer)
.addItems(items)
.applyDiscount(discount)
.build();
-
前缀/后缀模式:通过通用前缀或后缀表达功能,减少重复描述。
- 示例:
java
// 原名称:convertUserToUserDTO()
// 简化为:toDTO()
public UserDTO toDTO(User user) { ... }
5. 保留核心信息,舍弃冗余修饰词
-
去除冗余动词 :如
get
、process
、handle
等,通过方法位置或参数推断功能。- 示例:
java
// 原名称:handleUserRegistrationRequest()
// 简化为:registerUser()
public void registerUser(User user) { ... }
-
聚焦核心业务 :名称应体现"做什么 "而非"如何做"。
- 示例:
java
// 原名称:calculateTotalPriceIncludingTaxAndDiscount()
// 简化为:calculateTotal()
// 通过注释或文档说明包含税和折扣
原始名称 | 优化后 | 策略 |
---|---|---|
getCustomerInformationFromDatabaseUsingId |
findCustomerById() |
参数隐含(id )、领域术语(Customer ) |
validateUserRegistrationFormAndSaveToDatabase |
registerUser() |
拆分方法,聚焦核心动作 |
TransactionProcessorForECommerceOrders |
OrderTransactionProcessor |
上下文明确(ECommerce 是模块名) |
calculateMonthlySubscriptionCostBasedOnPlanTypeAndUserTier |
computeSubscriptionCost() |
参数隐含(planType , userTier ) |
注意事项
-
避免过度缩写 :确保缩写在团队中统一且易懂(如
Svc
代表 Service,但Svc
对新人可能不直观)。 -
保持一致性 :同一项目中命名风格需统一(如是否使用
CamelCase
或Snake_Case
)。 -
注释补充:对于非常规缩写或复杂逻辑,可通过注释或文档说明。
-
IDE辅助:利用 IDE 的自动补全功能(如 IntelliJ 的智能提示),减少长名称输入负
总结原则
-
优先上下文:在类/模块/参数中已包含的信息,方法名/变量名可省略。
-
领域术语优先:使用业务领域中的通用术语替代冗长描述。
-
拆分优先:复杂逻辑拆分为小模块,每个模块命名清晰。
-
可读性 > 简洁性:宁可稍长但明确,也不要过于晦涩的缩写。