编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • 质量保障

  • 产品思考

  • 软实力

  • 开发流程

  • Git应用

  • 技术模版

  • 技术规范

    • 技术规范
    • C++编程代码规范指南
    • Java编程代码规范指南
      • 01.代码规范概述
        • 1.1 为何需要代码规范
        • 1.2 规范的核心目标
        • 1.3 规范的演变历史
      • 02.命名规范设计
        • 2.1 包名命名规范
        • 2.2 类名命名规范
        • 2.3 方法命名规范
        • 2.4 变量命名规范
        • 2.5 常量命名规范
        • 2.6 命名反模式
      • 03.代码格式规范
        • 3.1 缩进与空格
        • 3.2 换行与对齐
        • 3.3 大括号风格
        • 3.4 空行与分隔
      • 04.注释规范设计
        • 4.1 注释的核心原则
        • 4.2 类注释规范
        • 4.3 方法注释规范
        • 4.4 行内注释规范
        • 4.5 TODO和FIXME
      • 05.编程实践规范
        • 5.1 异常处理规范
        • 5.2 空指针防御
        • 5.3 集合使用规范
        • 5.4 字符串处理规范
        • 5.5 并发编程规范
        • 5.6 防御性拷贝 【推荐】
      • 06.面向对象规范
        • 6.1 类设计规范
        • 6.2 接口设计规范
        • 6.3 继承与组合
        • 6.4 方法设计规范
        • 6.5 Record 类(Java 14+)【推荐】
        • 6.6 Sealed Classes(Java 17+)【推荐】
        • 6.7 Pattern Matching(Java 16+)【推荐】
      • 07.跨语言对比
        • 7.1 Java vs Kotlin
        • 7.2 Java vs Go
        • 7.3 通用编码原则
      • 08.日志规范(阿里规约)
        • 8.1 日志框架
        • 8.2 日志级别规范
        • 8.3 日志打印规范
      • 09.控制语句规范(阿里规约)
        • 9.1 switch 语句
        • 9.2 条件判断
        • 9.3 循环规范
      • 10.日期与时间(阿里规约)
      • 11.equals 与 hashCode(阿里规约)
      • 12.序列化规范
      • 13.枚举使用(阿里规约)
      • 14.数组与泛型补充
      • 15.MySQL 数据库规范(阿里规约)
      • 16.单元测试规范
      • 17.安全规约(阿里规约)
      • 18.工程结构规范
      • 19.Stream API 规范
        • 19.1 基本使用原则
        • 19.2 常见误用与改进
        • 19.3 性能注意事项
      • 20.Lombok 使用规范
        • 20.1 推荐使用的注解
        • 20.2 谨慎使用的注解
        • 20.3 禁止使用的注解
      • 21.性能优化规范
        • 21.1 字符串与集合
        • 21.2 对象创建与 GC
        • 21.3 数据库与 IO
        • 21.4 缓存策略 【推荐】
      • 22.工具链与自动化规范
        • 22.1 静态代码检查
        • 22.2 代码格式化
        • 22.3 CI 集成
        • 22.4 架构测试 【推荐】
      • 23.代码审查清单
      • 24.常见陷阱速查
        • 24.1 空指针陷阱
        • 24.2 集合陷阱
        • 24.3 并发陷阱
        • 24.4 性能陷阱
    • JavaScript编程规范指南
    • TypeScript编程规范指南
    • Python编程代码规范指南
    • Go编程代码规范指南
    • Kotlin编程代码规范指南
    • Swift编程代码规范指南
    • Rust编程代码规范指南
    • Shell编程代码规范指南
    • 项目代码提交规范
  • markdown

  • mermaid

  • license

  • 博客部署

  • 技术招聘

  • 测试经验

  • 技术
  • 技术规范
杨充
2020-03-15
目录

Java编程代码规范指南

# Java编程代码规范指南

# 目录介绍

  • 01.代码规范概述
    • 1.1 为何需要代码规范
    • 1.2 规范的核心目标
    • 1.3 规范的演变历史
  • 02.命名规范设计
    • 2.1 包名命名规范
    • 2.2 类名命名规范
    • 2.3 方法命名规范
    • 2.4 变量命名规范
    • 2.5 常量命名规范
    • 2.6 命名反模式
  • 03.代码格式规范
    • 3.1 缩进与空格
    • 3.2 换行与对齐
    • 3.3 大括号风格
    • 3.4 空行与分隔
  • 04.注释规范设计
    • 4.1 注释的核心原则
    • 4.2 类注释规范
    • 4.3 方法注释规范
    • 4.4 行内注释规范
    • 4.5 TODO和FIXME
  • 05.编程实践规范
    • 5.1 异常处理规范
    • 5.2 空指针防御
    • 5.3 集合使用规范
    • 5.4 字符串处理规范
    • 5.5 并发编程规范
    • 5.6 防御性拷贝
  • 06.面向对象规范
    • 6.1 类设计规范
    • 6.2 接口设计规范
    • 6.3 继承与组合
    • 6.4 方法设计规范
    • 6.5 Record 类
    • 6.6 Sealed Classes
    • 6.7 Pattern Matching
  • 07.跨语言对比
    • 7.1 Java vs Kotlin
    • 7.2 Java vs Go
    • 7.3 通用编码原则
  • 08.日志规范
  • 09.控制语句规范
  • 10.日期与时间规范
  • 11.equals与hashCode
  • 12.序列化规范
  • 13.枚举使用规范
  • 14.数组与泛型补充
  • 15.MySQL数据库规范
  • 16.单元测试规范
  • 17.安全规约
  • 18.工程结构规范
  • 19.Stream API 规范
    • 19.1 基本使用原则
    • 19.2 常见误用与改进
    • 19.3 性能注意事项
  • 20.Lombok 使用规范
    • 20.1 推荐使用的注解
    • 20.2 谨慎使用的注解
    • 20.3 禁止使用的注解
  • 21.性能优化规范
    • 21.1 字符串与集合
    • 21.2 对象创建与GC
    • 21.3 数据库与IO
    • 21.4 缓存策略
  • 22.工具链与自动化规范
    • 22.1 静态代码检查
    • 22.2 代码格式化
    • 22.3 CI 集成
    • 22.4 架构测试
  • 23.代码审查清单
  • 24.常见陷阱速查
    • 24.1 空指针陷阱
    • 24.2 集合陷阱
    • 24.3 并发陷阱
    • 24.4 性能陷阱

# 01.代码规范概述

# 1.1 为何需要代码规范

疑惑:代码能跑就行,为什么还要花时间制定和遵守规范?

答疑:代码的生命周期中,阅读时间远大于编写时间。据统计,开发者花在阅读代码上的时间是写代码的10倍以上。代码规范的本质是降低团队协作的认知成本。

论证——没有规范的代价:

开发者A的风格                    开发者B的风格
────────────────                ────────────────
public void getData(){          public void get_data()
  if(flag==true){               {
    return result;                if (flag)
  }                               {
}                                   return result;
                                  }
                                }
1
2
3
4
5
6
7
8
9

当两种风格混合在同一个项目中:

  1. 代码审查效率降低:关注点从逻辑转移到格式
  2. Bug隐蔽性增加:不一致的风格容易掩盖逻辑错误
  3. 新人上手成本增加:需要适应多种风格

结果:Google、阿里、华为等大厂都有严格的编码规范,且通过工具强制执行。

# 1.2 规范的核心目标

目标 说明
可读性 代码像散文一样流畅,一目了然
一致性 整个项目像一个人写的
可维护性 半年后自己还能看懂
健壮性 从编码层面减少Bug
可审查性 Code Review 聚焦逻辑而非格式

# 1.3 规范的演变历史

1996  Sun Microsystems 发布《Java Code Conventions》—— 第一份官方规范
  |
2009  Google 发布《Google Java Style Guide》—— 工业界最广泛采用
  |
2017  阿里巴巴发布《Java开发手册》(孤尽版) —— 国内影响力最大
  |
2018  Oracle 更新 Java SE 编码风格 —— 适配 Java 8+ 新特性
  |
2023  阿里发布《Java开发手册》黄山版 —— 适配 Java 17+、Record、sealed
1
2
3
4
5
6
7
8
9

核心参考标准:

  • Google Java Style Guide
  • 阿里巴巴Java开发手册
  • Oracle Code Conventions for the Java Programming Language
  • Effective Java(Joshua Bloch)

# 02.命名规范设计

# 2.1 包名命名规范

核心原则:全部小写,使用反域名命名法,层次分明。

// 正确示例
com.company.project.module.submodule
com.example.app.feature.login
com.example.app.data.repository

// 错误示例
com.Company.Project        // 不能有大写
com.example.app.my_module  // 不能有下划线
1
2
3
4
5
6
7
8

包结构设计建议:

com.example.app/
├── data/               // 数据层
│   ├── local/          // 本地数据源
│   ├── remote/         // 远程数据源
│   └── repository/     // 数据仓库
├── domain/             // 领域层
│   ├── model/          // 领域模型
│   └── usecase/        // 用例
├── presentation/       // 表现层
│   ├── view/           // 视图
│   └── viewmodel/      // ViewModel
└── utils/              // 工具类
1
2
3
4
5
6
7
8
9
10
11
12

# 2.2 类名命名规范

核心原则:大驼峰命名法(UpperCamelCase),名词或名词短语。

类型 命名规则 示例
普通类 名词,大驼峰 UserManager, OrderService
抽象类 Abstract 或 Base 前缀 AbstractParser, BaseActivity
接口 形容词/能力词,或 I 前缀 Serializable, ICallback
异常类 Exception 后缀 BusinessException, DataNotFoundException
测试类 被测类名 + Test UserManagerTest
工具类 Utils 或 Helper 后缀 StringUtils, DateHelper
枚举类 名词,大驼峰 OrderStatus, ColorType
// 正确
public class HttpClientFactory { }
public abstract class AbstractDataSource { }
public interface OnClickListener { }

// 错误
public class httpClient { }       // 首字母未大写
public class Manage_User { }      // 不能有下划线
public class Info { }             // 命名过于模糊
1
2
3
4
5
6
7
8
9

# 2.3 方法命名规范

核心原则:小驼峰命名法(lowerCamelCase),动词或动词短语。

// 获取类方法:get/find/query/fetch
public User getUserById(long id);
public List<Order> findOrdersByDate(Date date);

// 判断类方法:is/has/can/should
public boolean isEmpty();
public boolean hasPermission(String role);
public boolean canRetry();

// 设置类方法:set/update/modify
public void setName(String name);
public void updateProfile(Profile profile);

// 转换类方法:to/from/parse/format
public String toString();
public Order fromJson(String json);

// 回调类方法:on/handle/process
public void onClick(View view);
public void handleMessage(Message msg);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 2.4 变量命名规范

// 局部变量:小驼峰,有意义的名称
int userCount = 0;              // 正确
int cnt = 0;                    // 不推荐,缩写含义不清

// 成员变量:小驼峰(Android中常用 m 前缀)
private String mUserName;       // Android 风格
private String userName;        // 标准 Java 风格

// 布尔变量:is/has/can 前缀
private boolean isActive;
private boolean hasData;

// 集合变量:复数或集合类型后缀
private List<User> users;
private Map<String, Object> configMap;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

严禁使用的命名方式:

// 单字母变量(循环索引除外)
int a, b, c;           // 错误

// 拼音命名
String dianHua;         // 错误,应该用 phoneNumber
String shouJiHao;       // 错误

// 数字编号
String value1, value2;  // 错误,无法表达含义
1
2
3
4
5
6
7
8
9

# 2.5 常量命名规范

核心原则:全大写,下划线分隔。

// 正确
public static final int MAX_RETRY_COUNT = 3;
public static final String DEFAULT_CHARSET = "UTF-8";
public static final long CACHE_EXPIRE_TIME = 24 * 60 * 60 * 1000L;

// 错误
public static final int maxRetryCount = 3;     // 未全大写
public static final int MAX = 3;                // 命名过短,含义不清
1
2
3
4
5
6
7
8

# 2.6 命名反模式

反模式 示例 问题 改进
过度缩写 usrMgr 可读性差 userManager
含义不清 data, info, temp 无法理解用途 userData, orderInfo
类型冗余 nameString, ageInt 类型已知 name, age
否定命名 isNotEmpty 双重否定易混淆 isEmpty 反转
过长命名 getAllActiveUsersFromDatabaseByStatus 太冗长 findActiveUsersByStatus

# 03.代码格式规范

# 3.1 缩进与空格

// 使用4个空格缩进(不使用Tab)
public void processData(List<String> items) {
    for (String item : items) {
        if (item != null) {
            doSomething(item);
        }
    }
}

// 运算符两侧加空格
int result = a + b * c;
boolean isValid = (age >= 18) && (name != null);

// 逗号后加空格
public void init(String name, int age, boolean active) { }

// 类型转换后加空格
String text = (String) obj;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 3.2 换行与对齐

// 方法参数过长时换行
public void sendNotification(
        String userId,
        String title,
        String content,
        NotificationType type) {
    // ...
}

// 链式调用换行
List<String> result = users.stream()
        .filter(u -> u.isActive())
        .map(User::getName)
        .sorted()
        .collect(Collectors.toList());

// 条件表达式过长时换行
if (userStatus == Status.ACTIVE
        && userRole == Role.ADMIN
        && hasPermission(Permission.WRITE)) {
    // ...
}

// 单行长度不超过120个字符(Google规范)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 3.3 大括号风格

Java统一采用 K&R风格(Egyptian Brackets):

// 正确:左大括号不换行
public class UserService {

    public void process() {
        if (condition) {
            doSomething();
        } else {
            doOther();
        }
    }
}

// 错误:左大括号换行(C#风格,Java不推荐)
public class UserService
{
    public void process()
    {
        // ...
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

特殊情况:空方法体可以简写

public void onPause() { }
1

# 3.4 空行与分隔

public class UserService {

    // 成员变量之间不需要空行(同组)
    private final UserRepository userRepo;
    private final CacheManager cache;

    // 不同逻辑组之间用一个空行分隔
    private static final int MAX_RETRY = 3;

    // 构造方法与成员变量之间空一行
    public UserService(UserRepository repo, CacheManager cache) {
        this.userRepo = repo;
        this.cache = cache;
    }

    // 方法之间空一行
    public User getUser(long id) {
        // 方法内逻辑分组用空行
        User cached = cache.get(id);
        if (cached != null) {
            return cached;
        }

        // 不同逻辑块之间空一行
        User user = userRepo.findById(id);
        cache.put(id, user);
        return user;
    }

    public void deleteUser(long id) {
        // ...
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 04.注释规范设计

# 4.1 注释的核心原则

好的代码是自文档化的,注释是用来解释"为什么",而不是"做了什么"。

// 差的注释:复述代码
i++; // i加1

// 好的注释:解释意图
i++; // 跳过CSV文件的标题行

// 差的注释:过时信息
// 调用支付接口(注:已改为异步调用)  ← 什么时候改的?现在还是异步吗?
processPayment();

// 好的注释:记录决策原因
// 使用重试机制,因为第三方支付接口在高峰期偶尔超时(2020-03确认的问题)
processPaymentWithRetry(MAX_RETRY);
1
2
3
4
5
6
7
8
9
10
11
12
13

# 4.2 类注释规范

/**
 * 用户服务类,负责用户相关的核心业务逻辑。
 *
 * <p>主要职责包括:
 * <ul>
 *   <li>用户信息的CRUD操作</li>
 *   <li>用户认证与授权</li>
 *   <li>用户数据缓存管理</li>
 * </ul>
 *
 * <p>线程安全性:该类是线程安全的,内部通过 {@code synchronized} 保证并发访问安全。
 *
 * @author yc
 * @since 1.0
 */
public class UserService {
    // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 4.3 方法注释规范

/**
 * 根据用户ID查询用户信息。
 *
 * <p>优先从缓存中获取,缓存未命中时查询数据库。
 * 查询结果会自动写入缓存,缓存过期时间为 {@value #CACHE_TTL} 秒。
 *
 * @param userId 用户唯一标识,不能为null
 * @return 用户对象,如果用户不存在则返回null
 * @throws IllegalArgumentException 如果userId为null
 * @throws DataAccessException      如果数据库访问异常
 */
public User getUserById(@NonNull Long userId) {
    // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 4.4 行内注释规范

// 1. 行内注释放在代码上方,而非行尾(长注释场景)
// 使用双重检查锁实现单例,volatile防止指令重排
private volatile static Singleton instance;

// 2. 短注释可以放在行尾
int timeout = 30;  // 单位:秒

// 3. 禁止无意义注释
String name;  // 定义name变量  ← 这种注释删掉
1
2
3
4
5
6
7
8
9

# 4.5 TODO和FIXME

// TODO 标记待完成的功能
// TODO(yc): 添加分页查询支持,预计2.0版本实现
public List<User> getAllUsers() {
    return userRepo.findAll(); // 当前无分页
}

// FIXME 标记已知Bug
// FIXME(yc): 当userId为Long.MAX_VALUE时会溢出,需要增加边界检查
public long calculateHash(long userId) {
    return userId * 31 + offset;
}
1
2
3
4
5
6
7
8
9
10
11

# 05.编程实践规范

# 5.1 异常处理规范

// 1. 不要捕获所有异常
// 错误
try {
    process();
} catch (Exception e) {
    e.printStackTrace();  // 吞掉异常,生产环境看不到
}

// 正确
try {
    process();
} catch (IOException e) {
    logger.error("处理数据失败, file={}", filePath, e);
    throw new BusinessException("数据处理失败", e);
}

// 2. finally 中不要使用 return
// 错误:finally中的return会覆盖try中的return
try {
    return computeResult();
} finally {
    return defaultValue;  // 永远返回这个值!
}

// 3. 使用 try-with-resources(Java 7+)
// 正确
try (InputStream is = new FileInputStream(file);
     BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
    return reader.readLine();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 5.2 空指针防御

// 1. 使用 Optional(Java 8+)
public Optional<User> findUser(long id) {
    return Optional.ofNullable(userRepo.findById(id));
}

// 调用方
String name = findUser(id)
        .map(User::getName)
        .orElse("未知用户");

// 2. 方法参数校验
public void updateUser(@NonNull User user) {
    Objects.requireNonNull(user, "user不能为null");
    Objects.requireNonNull(user.getName(), "用户名不能为null");
    // ...
}

// 3. 集合返回空集合而非null
public List<Order> getOrders(long userId) {
    List<Order> orders = orderRepo.findByUserId(userId);
    return orders != null ? orders : Collections.emptyList();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 5.3 集合使用规范

// 1. 指定集合初始容量(避免多次扩容)
// 已知大小时指定容量
List<User> users = new ArrayList<>(expectedSize);
Map<String, Object> map = new HashMap<>(16);  // 初始容量为2的幂

// 2. 使用 isEmpty() 而非 size() == 0
if (list.isEmpty()) { }       // 正确:O(1)
if (list.size() == 0) { }     // 不推荐:某些集合size()是O(n)

// 3. 遍历时不要修改集合
// 错误:ConcurrentModificationException
for (String item : list) {
    if (item.equals("remove")) {
        list.remove(item);
    }
}
// 正确:使用 Iterator 或 removeIf
list.removeIf(item -> item.equals("remove"));

// 4. 不可变集合
List<String> immutable = List.of("a", "b", "c");          // Java 9+
List<String> immutable2 = Collections.unmodifiableList(list); // Java 8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 5.4 字符串处理规范

// 1. 字符串比较使用 equals,常量放前面
// 正确:避免NPE
if ("active".equals(status)) { }

// 错误:status为null时NPE
if (status.equals("active")) { }

// 2. 字符串拼接
// 少量拼接:直接用 +(编译器自动优化)
String msg = "Hello, " + name + "!";

// 循环中拼接:使用 StringBuilder
StringBuilder sb = new StringBuilder(256);
for (String item : items) {
    sb.append(item).append(",");
}

// 3. 字符串格式化
String msg = String.format("用户%s的订单数:%d", userName, orderCount);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 5.5 并发编程规范

// 1. 线程池不允许用 Executors 创建(阿里规约)
// 错误:无界队列可能OOM
ExecutorService pool = Executors.newFixedThreadPool(10);

// 正确:手动创建,明确参数
ExecutorService pool = new ThreadPoolExecutor(
        5,                                  // 核心线程数
        10,                                 // 最大线程数
        60L, TimeUnit.SECONDS,              // 空闲超时
        new LinkedBlockingQueue<>(1000),     // 有界队列
        new ThreadPoolExecutor.CallerRunsPolicy()  // 拒绝策略
);

// 2. 使用 volatile 保证可见性
private volatile boolean running = true;

// 3. 使用 ConcurrentHashMap 而非 Collections.synchronizedMap
Map<String, Object> map = new ConcurrentHashMap<>();

// 4. 加锁顺序一致,避免死锁
// 始终按照相同的顺序获取锁
synchronized (lockA) {
    synchronized (lockB) {
        // ...
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 5.6 防御性拷贝 【推荐】

// ✅ 构造时对可变参数做防御性拷贝
public class Period {
    private final Date start;
    private final Date end;

    public Period(Date start, Date end) {
        // ❌ 直接赋值——外部仍持有引用,可以修改
        // this.start = start;
        // ✅ 防御性拷贝
        this.start = new Date(start.getTime());
        this.end = new Date(end.getTime());
        if (this.start.compareTo(this.end) > 0) {
            throw new IllegalArgumentException("start after end");
        }
    }

    // ✅ getter 也返回拷贝,防止外部修改内部状态
    public Date getStart() {
        return new Date(start.getTime());
    }
}

// ✅ 集合字段同理——不直接暴露内部集合
public class OrderList {
    private final List<Order> orders = new ArrayList<>();

    // ✅ 返回不可修改视图
    public List<Order> getOrders() {
        return Collections.unmodifiableList(orders);
    }

    // ✅ 或用 List.copyOf(Java 10+,真不可变)
    public List<Order> getOrdersCopy() {
        return List.copyOf(orders);
    }
}

// ❌ 直接暴露内部集合——外部可以随意增删
public List<Order> getOrders() {
    return orders;   // 危险!
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

防御性拷贝适用场景:

  • 构造器接收可变参数(Date、Collection、数组等)
  • getter 返回可变内部状态
  • 跨层传递对象(Controller → Service → DAO)
  • 注意:不可变类型(String、基本类型包装类、LocalDate)不需要拷贝

# 06.面向对象规范

# 6.1 类设计规范

// 1. 类的成员排列顺序
public class UserService {
    // ① 静态常量
    private static final String TAG = "UserService";

    // ② 静态变量
    private static UserService instance;

    // ③ 成员变量
    private final UserRepository userRepo;
    private String currentUser;

    // ④ 构造方法
    public UserService(UserRepository repo) {
        this.userRepo = repo;
    }

    // ⑤ 公有方法
    public User getUser(long id) { }

    // ⑥ 私有方法
    private void validate(User user) { }

    // ⑦ 内部类 / 内部接口
    private static class CacheEntry { }
}

// 2. 类的行数建议不超过500行
// 3. 方法的行数建议不超过80行
// 4. 方法参数不超过5个,超过则封装为对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 6.2 接口设计规范

// 1. 接口方法默认 public abstract,不需要显式声明
public interface UserCallback {
    void onSuccess(User user);        // 正确
    public abstract void onError();    // 冗余
}

// 2. 接口常量默认 public static final
public interface Constants {
    int MAX_SIZE = 100;  // 等同于 public static final int MAX_SIZE = 100;
}

// 3. Java 8+ 可以有 default 方法
public interface Logger {
    void log(String message);

    default void debug(String message) {
        log("[DEBUG] " + message);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 6.3 继承与组合

// 优先使用组合而非继承
// 不推荐:继承导致强耦合
public class OrderService extends BaseService { }

// 推荐:组合更灵活
public class OrderService {
    private final BaseService baseService;

    public OrderService(BaseService baseService) {
        this.baseService = baseService;
    }
}

// 继承的合理场景:IS-A 关系且需要多态
public abstract class Shape {
    public abstract double area();
}
public class Circle extends Shape {
    @Override
    public double area() { return Math.PI * r * r; }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 6.4 方法设计规范

// 1. 方法应该只做一件事
// 错误:一个方法做了太多事
public void processOrder(Order order) {
    validate(order);
    calculatePrice(order);
    deductStock(order);
    sendNotification(order);
    updateStatistics(order);
}
// 方法体过大时应拆分子方法

// 2. 返回值语义明确
// 错误:用 -1 表示未找到
public int findIndex(String key) {
    return -1; // 魔法数字
}
// 正确:使用 Optional 或定义常量
public OptionalInt findIndex(String key) {
    return OptionalInt.empty();
}

// 3. 方法参数使用 final(防止意外修改)
public String format(final String input) {
    // input 不会被意外重新赋值
    return input.trim().toLowerCase();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 6.5 Record 类(Java 14+)【推荐】

// ✅ 纯数据载体:用 Record 替代传统 POJO
public record UserDTO(Long id, String name, String email) {
    // 自动生成:构造器、equals、hashCode、toString、getter
    // 字段不可变(final),无 setter
}

// 等效的传统写法(约 60 行):
// public class UserDTO {
//     private final Long id; ...
//     public UserDTO(Long id, String name, String email) { ... }
//     public Long getId() { return id; }
//     public boolean equals(Object o) { ... }  // 10+ 行
//     public int hashCode() { ... }            // 5+ 行
//     public String toString() { ... }         // 5+ 行
// }

// ✅ Record 可以加紧凑构造器做参数校验
public record PositivePoint(int x, int y) {
    public PositivePoint {
        if (x < 0 || y < 0) {
            throw new IllegalArgumentException("坐标不能为负");
        }
    }
}

// ✅ Record 适合场景:API 返回对象、配置对象、事件消息
// ❌ Record 不适合:JPA Entity(需要可变性)、复杂业务对象(继承体系)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 6.6 Sealed Classes(Java 17+)【推荐】

// ✅ 明确限定子类范围——禁止外部随意扩展
public sealed class Payment
        permits CardPayment, WechatPayment, AliPayment {
}

public final class CardPayment extends Payment { }
public final class WechatPayment extends Payment { }
public sealed class AliPayment extends Payment   // 可以继续 sealed
        permits AliH5Payment, AliAppPayment { }

// ✅ 配合 switch 表达式,编译器检查全覆盖
double calcFee(Payment p) {
    return switch (p) {
        case CardPayment c   -> c.amount() * 0.01;
        case WechatPayment w -> w.amount() * 0.006;
        case AliPayment a    -> a.amount() * 0.007;
        // 不需要 default——编译器强制全覆盖
    };
}

// ❌ 传统写法无法限制子类——谁都能 extends
public class Payment { }  // 任意包都可以子类化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 6.7 Pattern Matching(Java 16+)【推荐】

// ✅ instanceof 模式匹配(Java 16)
// ❌ 传统写法:强转 + 声明变量
if (obj instanceof String) {
    String s = (String) obj;
    System.out.println(s.length());
}

// ✅ 一行搞定
if (obj instanceof String s) {
    System.out.println(s.length());
}

// ✅ switch 模式匹配(Java 17 preview → 21 正式)
Object obj = // ...
String result = switch (obj) {
    case Integer i   -> "整数: " + i;
    case String s    -> "字符串长度: " + s.length();
    case Long l      -> "长整型: " + l;
    case null        -> "null 值";
    default          -> "未知类型";
};

// ✅ 带守卫(when)的模式匹配(Java 17 preview+)
switch (obj) {
    case String s when s.length() > 10 -> handleLong(s);
    case String s                      -> handleShort(s);
    default                            -> handleOther(obj);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 07.跨语言对比

# 7.1 Java vs Kotlin

规范项 Java Kotlin
命名风格 小驼峰/大驼峰 相同
空安全 需要手动判空 ? 语法糖
数据类 手写 getter/setter data class
单例 双重检查锁/枚举 object 关键字
字符串模板 String.format "Hello, $name"
异常 checked + unchecked 仅 unchecked
// Kotlin 风格
data class User(
    val name: String,
    val age: Int,
    val email: String? = null  // 可空类型
)

// Java 风格(等效)
public class User {
    private final String name;
    private final int age;
    private final String email;  // 需手动处理null
    // + getter, equals, hashCode, toString...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 7.2 Java vs Go

规范项 Java Go
命名风格 camelCase camelCase(导出用PascalCase)
大括号 K&R风格 强制K&R
异常处理 try-catch error返回值
接口 显式实现 隐式实现(鸭子类型)
泛型 类型擦除 1.18+具化泛型
格式化 自行配置 gofmt 统一
// Go 风格:错误处理
func GetUser(id int64) (*User, error) {
    user, err := repo.FindById(id)
    if err != nil {
        return nil, fmt.Errorf("查询用户失败: %w", err)
    }
    return user, nil
}
1
2
3
4
5
6
7
8

# 7.3 通用编码原则

无论使用哪种语言,以下原则都是通用的:

  1. DRY(Don't Repeat Yourself):不要重复自己
  2. KISS(Keep It Simple, Stupid):保持简单
  3. YAGNI(You Ain't Gonna Need It):不要过度设计
  4. Fail Fast:尽早暴露错误
  5. Defensive Programming:防御性编程
┌─────────────┬────────────────────────────────────────────┐
│   原则       │              核心要义                       │
├─────────────┼────────────────────────────────────────────┤
│   命名      │  名字即文档,见名知意                         │
│   格式      │  统一风格,工具强制执行                       │
│   注释      │  解释Why,不解释What                         │
│   异常      │  不吞异常,不滥捕获                          │
│   空安全    │  防御在前,Optional优先                      │
│   并发      │  明确线程模型,避免共享可变状态                │
│   设计      │  高内聚低耦合,优先组合                       │
└─────────────┴────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11

# 08.日志规范(阿里规约)

# 8.1 日志框架

应用中不可直接使用日志系统(Log4j、Logback)中的API,应依赖SLF4J门面:

// ✅ SLF4J 门面
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger log = LoggerFactory.getLogger(MyClass.class);

// ❌ 直接使用 Log4j
import org.apache.log4j.Logger;
1
2
3
4
5
6
7

# 8.2 日志级别规范

级别 场景 说明
ERROR 影响到程序正常运行、需要人工介入 第三方服务不可用、数据库连接失败
WARN 可恢复的异常、潜在风险 配置缺失使用默认值、重试成功
INFO 关键流程节点、外部调用 服务启动、重要业务操作、RPC调用
DEBUG 调试信息 方法入参出参、中间变量
// ✅ 正确使用
log.error("调用支付服务失败, orderId={}", orderId, e);
log.warn("配置项未设置, 使用默认值 timeout={}ms", DEFAULT_TIMEOUT);
log.info("订单创建成功, orderId={}, userId={}, amount={}", orderId, userId, amount);
log.debug("查询条件: {}", query);

// ❌ 错误使用
log.info("处理完成");  // 无关键信息,无法排查问题
1
2
3
4
5
6
7
8

# 8.3 日志打印规范

// ✅ 使用占位符,避免字符串拼接
log.info("用户登录, userId={}, ip={}", userId, ip);

// ❌ 字符串拼接(即使级别不匹配也会执行拼接)
log.debug("用户数据: " + user.toString());

// ✅ 条件日志(仅在需要时计算)
if (log.isDebugEnabled()) {
    log.debug("详细数据: {}", expensiveComputation());
}

// ✅ 异常日志必须包含堆栈
log.error("处理订单失败, orderId={}", orderId, e);  // e 作为最后参数

// ❌ 只打印 message,丢失堆栈
log.error("处理订单失败: " + e.getMessage());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 09.控制语句规范(阿里规约)

# 9.1 switch 语句

// ✅ 每个 case 必须有 break/return,或用 switch 表达式(Java 14+)
String typeName = switch (type) {
    case PAYMENT -> "支付订单";
    case REFUND  -> "退款订单";
    default      -> "未知类型";
};

// 传统写法必须写 break 并注释 fall-through
switch (type) {
    case PAYMENT:
        // fall through  // 明确注释
    case REFUND:
        process();
        break;
    default:
        break;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 9.2 条件判断

// ✅ 避免 if-else 层级过深(不超过3层)
// 使用卫语句提前返回
public void process(Order order) {
    if (order == null) {
        log.warn("订单为空");
        return;
    }
    if (!order.isValid()) {
        log.warn("无效订单: {}", order.getId());
        return;
    }
    if (order.isProcessed()) {
        return;
    }
    // 主逻辑
    doProcess(order);
}

// ✅ 复杂条件提取为方法
if (isEligibleForDiscount(user, order)) {
    applyDiscount(order);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 9.3 循环规范

// ✅ 使用 for-each 遍历
for (String item : list) {
    process(item);
}

// ✅ 不要在循环中执行耗时操作(数据库查询、RPC调用)
// 批量查询替代循环查询
List<Long> ids = orders.stream().map(Order::getUserId).collect(toList());
Map<Long, User> userMap = userService.batchGet(ids);  // 一次查询
1
2
3
4
5
6
7
8
9

# 10.日期与时间(阿里规约)

// ✅ Java 8+ 使用 java.time
LocalDate today = LocalDate.now();
LocalDateTime now = LocalDateTime.now();
ZonedDateTime zonedNow = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));

// ✅ 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String dateStr = now.format(formatter);

// ✅ 计算
LocalDate nextWeek = today.plusWeeks(1);
long days = ChronoUnit.DAYS.between(start, end);

// ❌ 禁止使用 System.currentTimeMillis() 直接做日期计算
// ❌ SimpleDateFormat 线程不安全,禁止作为静态变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 11.equals 与 hashCode(阿里规约)

// ✅ 重写 equals 必须重写 hashCode
// ✅ equals 自反性、对称性、传递性、一致性
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof User user)) return false;  // Java 16+ pattern matching
    return Objects.equals(id, user.id);
}

@Override
public int hashCode() {
    return Objects.hash(id);
}

// ✅ 使用 Objects.equals 避免 NPE
if (Objects.equals(a, b)) { ... }  // 而非 a.equals(b)

// ❌ equals 参数不能用除 Object 外的类型(否则是重载不是重写)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 12.序列化规范

// ✅ 显式指定 serialVersionUID
public class UserDTO implements Serializable {
    private static final long serialVersionUID = 1L;
}

// ✅ Jackson 注解(推荐,不依赖 Serializable)
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class UserDTO {
    private Long id;
    
    @JsonProperty("user_name")  // JSON字段名不同于Java字段名
    private String userName;
    
    @JsonIgnore  // 不序列化
    private String password;
    
    @JsonInclude(Include.NON_NULL)  // null 不序列化
    private String email;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 13.枚举使用(阿里规约)

// ✅ 枚举命名全大写,也可以用 Enum 替代常量类
public enum OrderStatus {
    PENDING("待支付"),
    PAID("已支付"),
    SHIPPED("已发货"),
    CANCELLED("已取消");

    private final String desc;
    OrderStatus(String desc) { this.desc = desc; }
}

// ✅ 枚举方法:每个常量可以有自己的行为
public enum Operation {
    PLUS  { double apply(double a, double b) { return a + b; } },
    MINUS { double apply(double a, double b) { return a - b; } };

    abstract double apply(double a, double b);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 14.数组与泛型补充

// ✅ 使用 List 优于数组(泛型兼容性更好)
// ❌ 数组协变,运行时可能 ClassCastException
Object[] arr = new String[1];
arr[0] = 1;  // ArrayStoreException 运行时

// ✅ 使用泛型集合
List<String> list = new ArrayList<>();

// ✅ 数组转 List 注意事项
// ❌ Arrays.asList() 返回固定大小,不可 add/remove
List<String> fixed = Arrays.asList("a", "b");
// ✅ 可变 List
List<String> mutable = new ArrayList<>(Arrays.asList("a", "b"));
1
2
3
4
5
6
7
8
9
10
11
12
13

# 15.MySQL 数据库规范(阿里规约)

-- ✅ 表名/字段名:小写 + 下划线
CREATE TABLE user_order (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键',
    user_id BIGINT UNSIGNED NOT NULL COMMENT '用户ID',
    order_no VARCHAR(64) NOT NULL COMMENT '订单号',
    amount DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT '金额',
    status TINYINT NOT NULL DEFAULT 0 COMMENT '状态',
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    INDEX idx_user_id (user_id),
    UNIQUE INDEX uk_order_no (order_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户订单表';
1
2
3
4
5
6
7
8
9
10
11
12
13
// ✅ 不使用 SELECT *
// ✅ 必须使用参数化查询,防止 SQL 注入
String sql = "SELECT id, name, email FROM user WHERE id = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setLong(1, userId);

// ❌ 直接拼接 SQL
String sql = "SELECT * FROM user WHERE name = '" + name + "'";  // SQL注入风险
1
2
3
4
5
6
7
8

# 16.单元测试规范

// ✅ JUnit 5 + Mockito
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {

    @Mock
    private OrderRepository repository;
    
    @InjectMocks
    private OrderService service;

    @Test
    @DisplayName("创建订单成功")
    void shouldCreateOrderSuccessfully() {
        // Given
        CreateOrderRequest request = new CreateOrderRequest(1L, "item", 100);
        when(repository.save(any())).thenReturn(mockOrder);
        
        // When
        Order result = service.create(request);
        
        // Then
        assertNotNull(result);
        assertEquals(OrderStatus.PENDING, result.getStatus());
        verify(repository).save(any());
    }
    
    // ✅ 测试异常场景
    @Test
    void shouldThrowWhenUserNotFound() {
        when(repository.findById(1L)).thenReturn(Optional.empty());
        assertThrows(UserNotFoundException.class, () -> service.getUser(1L));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

测试覆盖率:

  • 核心业务方法 100%
  • 分支覆盖(每个 if 的两条路径都要测)
  • 异常路径必须覆盖

# 17.安全规约(阿里规约)

// ✅ 敏感数据脱敏
public class UserVO {
    private String name;
    
    @JsonSerialize(using = PhoneDesensitize.class)
    private String phone;  // 138****1234
    
    @JsonIgnore  // 密码绝不返回前端
    private String password;
}

// ✅ 参数校验
@PostMapping("/users")
public Result createUser(@Valid @RequestBody CreateUserRequest request) {
    // @Valid 触发 javax.validation 校验
}

public class CreateUserRequest {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 20)
    private String name;
    
    @Email
    private String email;
    
    @Pattern(regexp = "^1[3-9]\\d{9}$")
    private String phone;
}

// ✅ 权限控制
@PreAuthorize("hasRole('ADMIN')")  // Spring Security
public Result deleteUser(Long id) { ... }

// ❌ 禁止在代码中硬编码密钥/密码
private static final String SECRET = "my-secret-key";  // 危险!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 18.工程结构规范

com.company.project
├── controller/     # HTTP接口层,薄薄一层只做参数转换
├── service/        # 业务逻辑层
│   └── impl/
├── repository/     # 数据访问层(DAO)
├── model/
│   ├── entity/     # 数据库实体
│   ├── dto/        # 数据传输对象
│   └── vo/         # 视图对象
├── config/         # 配置类
├── common/
│   ├── exception/  # 自定义异常
│   ├── constant/   # 常量
│   └── util/       # 工具类
└── Application.java

# 分层调用:Controller → Service → Repository
# 禁止反向依赖、同层循环依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 19.Stream API 规范

# 19.1 基本使用原则

// ✅ 优先使用方法引用
List<String> names = users.stream()
        .map(User::getName)
        .collect(Collectors.toList());

// ❌ 冗余的 lambda
List<String> names = users.stream()
        .map(u -> u.getName())
        .collect(Collectors.toList());

// ✅ 复杂操作应提取为方法
String result = users.stream()
        .filter(this::isActive)
        .map(this::formatUser)
        .collect(Collectors.joining(","));

// ❌ Stream 中副作用过多(日志、状态修改混在 Stream 里)
users.stream()
        .peek(u -> log.info("处理用户 {}", u.getId()))  // 仅调试用
        .filter(User::isActive)
        .forEach(u -> u.setStatus(1));  // ❌ forEach 中修改状态不清真
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 19.2 常见误用与改进

// ❌ Stream 中抛检查异常很丑
List<String> result = paths.stream()
        .map(path -> {
            try {
                return Files.readString(Path.of(path));
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        })
        .collect(toList());

// ✅ 把异常处理提取为方法
private String readFileSafe(String path) {
    try { return Files.readString(Path.of(path)); }
    catch (IOException e) { throw new UncheckedIOException(e); }
}
List<String> result = paths.stream().map(this::readFileSafe).collect(toList());

// ❌ 用 forEach 代替 for 循环(没有简洁性提升)
users.stream().forEach(u -> process(u));  // Stream 创建有开销

// ✅ 直接用 for-each(简单场景)
for (User u : users) {
    process(u);
}

// Stream 适用场景:filter + map + collect 链条 > 2 步
// for-each 适用场景:单步遍历 + 简单操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 19.3 性能注意事项

// ❌ 每次调用都创建新 Stream(热路径中避免)
for (int i = 0; i < 1000; i++) {
    long count = users.stream().filter(User::isActive).count();  // 创建1000个Stream对象
}

// ✅ 提前计算,复用结果
long activeCount = users.stream().filter(User::isActive).count();
for (int i = 0; i < 1000; i++) {
    doSomething(activeCount);
}

// ✅ 基本类型用特化 Stream(IntStream、LongStream,避免装箱)
IntStream.range(0, 100).sum();          // ✅ 无装箱
Stream.of(1, 2, 3).mapToInt(i -> i);     // ✅ 显式转换
Stream.of(1, 2, 3).reduce(0, Integer::sum);  // ❌ 每次 reduce 装箱
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 20.Lombok 使用规范

# 20.1 推荐使用的注解

// ✅ @Data —— 用在纯数据类(DTO/VO/Entity)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDTO {
    private Long id;
    private String name;
    private Integer age;
}

// ✅ @Builder —— 构建复杂对象(推荐用于多参数构造)
@Builder
public class OrderRequest {
    private Long userId;
    private String productCode;
    private BigDecimal amount;
    private String couponCode;   // 可选
    private String remark;       // 可选
}

// 调用方:意图清晰,参数可选
OrderRequest req = OrderRequest.builder()
        .userId(1L)
        .productCode("SKU001")
        .amount(new BigDecimal("99.00"))
        .remark("加急配送")
        .build();

// ✅ @Slf4j —— 日志声明
@Slf4j
public class OrderService {
    public void process(Order order) {
        log.info("处理订单: {}", order.getId());
    }
}

// ✅ @RequiredArgsConstructor —— 注入 final 字段(Spring 推荐)
@Service
@RequiredArgsConstructor
public class OrderService {
    private final OrderRepository orderRepo;  // 构造器注入
    private final PaymentGateway paymentGateway;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# 20.2 谨慎使用的注解

// ⚠️ @EqualsAndHashCode —— 继承体系中有坑
// 仅用于无继承关系的简单 POJO

// ⚠️ @ToString —— 注意循环引用
@Data
@ToString(exclude = "parent")  // 排除双向关联字段
public class Category {
    private Long id;
    private String name;
    private Category parent;          // 排除,避免递归爆栈
    private List<Category> children;
}

// ⚠️ @Getter/@Setter —— 如非必要,不开放不必要的 setter
public class Order {
    @Getter private Long id;
    @Getter private BigDecimal amount;
    @Getter private OrderStatus status;
    // 不生成 setter —— 通过业务方法修改状态
    public void pay() { this.status = OrderStatus.PAID; }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 20.3 禁止使用的注解

// ❌ @SneakyThrows —— 吞掉编译期异常检查,破坏异常体系
// @SneakyThrows
// public void readFile() { Files.readString(path); }

// ❌ @Cleanup —— 不如 try-with-resources 清晰
// try (var reader = new BufferedReader(...)) { }  ← 更标准,一眼看出资源释放

// ❌ @NonNull —— 不如 @lombok.NonNull 明确,更推荐 javax.validation 或 Objects.requireNonNull
1
2
3
4
5
6
7
8

# 21.性能优化规范

# 21.1 字符串与集合

// ✅ 循环拼接:必须用 StringBuilder
StringBuilder sb = new StringBuilder(expectedSize);
for (String item : list) {
    sb.append(item).append(delimiter);
}
String result = sb.toString();

// ✅ 指定初始容量,减少扩容
List<String> list = new ArrayList<>(1000);       // 已知大致大小
Map<String, User> map = new HashMap<>(256);      // 2的幂
Set<String> set = new HashSet<>(expectedSize);

// ✅ String.intern() 谨慎使用 —— 仅用于大量重复字符串
// 太多 intern 会撑爆 StringTable(默认 60013 个)

// ✅ 避免在循环中使用正则
// ❌ 每次循环都编译 Pattern
for (String s : list) {
    s.matches("\\d{4}-\\d{2}-\\d{2}");
}
// ✅ 提前编译
private static final Pattern DATE_PATTERN = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 21.2 对象创建与 GC

// ✅ 局部变量优先用基本类型(减少堆分配)
int count = 0;              // ✅ 栈上,轻量
Integer count = 0;          // ❌ 堆分配,自动装箱

// ✅ 对象池:常用小对象可复用(Integer缓存 -128~127)
Integer a = 127, b = 127;
System.out.println(a == b);  // true(缓存池命中)

// ✅ 懒加载:不立即创建昂贵对象
private volatile ExpensiveObject cache;  // volatile 可见性

// ✅ try-with-resources 确保流关闭
try (var is = new FileInputStream(file);
     var reader = new BufferedReader(new InputStreamReader(is))) {
    return reader.lines().collect(toList());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 21.3 数据库与 IO

// ✅ 批量操作:一条SQL替代N条
// ❌ N次查询
for (Long id : ids) {
    orderRepo.findById(id);  // 100次往返!
}
// ✅ 1次查询
List<Order> orders = orderRepo.findByIdIn(ids);

// ✅ 分页查询:必加 limit
// ❌ SELECT * FROM orders WHERE user_id = ?
// ✅ SELECT * FROM orders WHERE user_id = ? LIMIT 100 OFFSET ?

// ✅ 连接池复用:不要每次 new Connection
// Spring Boot 默认 HikariCP,配置合理即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 21.4 缓存策略 【推荐】

// ✅ 本地缓存:Caffeine(推荐,比 Guava Cache 更优)
private final Cache<Long, User> userCache = Caffeine.newBuilder()
        .maximumSize(10_000)                 // 最大条目
        .expireAfterWrite(30, TimeUnit.MINUTES)  // 写入后过期
        .recordStats()                        // 开启统计
        .build();

User user = userCache.get(userId, key -> userRepo.findById(key));

// ✅ 多级缓存:本地 + Redis
public User getUserWithCache(Long id) {
    // L1:本地缓存
    User user = localCache.getIfPresent(id);
    if (user != null) return user;

    // L2:Redis 缓存
    String json = redisTemplate.opsForValue().get("user:" + id);
    if (json != null) {
        user = objectMapper.readValue(json, User.class);
        localCache.put(id, user);
        return user;
    }

    // L3:数据库
    user = userRepo.findById(id).orElse(null);
    if (user != null) {
        redisTemplate.opsForValue().set("user:" + id, toJson(user), 1, TimeUnit.HOURS);
        localCache.put(id, user);
    }
    return user;
}

// ✅ 缓存穿透防御:空值缓存
User user = userCache.get(id, key -> {
    User u = userRepo.findById(key).orElse(null);
    return u != null ? u : User.EMPTY;  // 缓存空对象,防穿透
});

// ❌ 无过期/无上限的缓存——OOM 隐患
Map<Long, User> cache = new HashMap<>();  // 越放越多
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 22.工具链与自动化规范

# 22.1 静态代码检查

工具 用途 集成方式
Checkstyle 代码风格检查(命名、空格、大括号) Maven/Gradle 插件,CI 中执行
SpotBugs 字节码级别的 Bug 检测 Maven/Gradle 插件
SonarQube 代码质量综合扫描(Bug/漏洞/坏味道) CI 流水线
PMD 代码坏味道检测(重复代码、过长方法) Maven 插件
<!-- pom.xml Checkstyle 配置 -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>3.3.0</version>
    <configuration>
        <configLocation>checkstyle.xml</configLocation>
        <failOnViolation>true</failOnViolation>  <!-- CI 中设为 true -->
    </configuration>
    <executions>
        <execution>
            <phase>validate</phase>
            <goals><goal>check</goal></goals>
        </execution>
    </executions>
</plugin>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 22.2 代码格式化

<!-- .editorconfig:跨编辑器统一格式 -->
[*.java]
indent_style = space
indent_size = 4
max_line_length = 120
1
2
3
4
5
# Spotless:一键格式化(Google Java Format 风格)
./mvnw spotless:apply
1
2

# 22.3 CI 集成

# GitHub Actions 示例
- name: Code Quality Check
  run: |
    ./mvnw checkstyle:check    # 风格检查
    ./mvnw spotbugs:check      # Bug 检测
    ./mvnw test                # 单元测试
1
2
3
4
5
6

# 22.4 架构测试 【推荐】

用 ArchUnit 在单元测试里强制架构约束:

@Test
void controllers_should_not_depend_on_repositories_directly() {
    classes().that().resideInAPackage("..controller..")
        .should().onlyDependOnClassesThat()
        .resideInAnyPackage("..service..", "..dto..", "java..")
        .check(classes);
}

@Test
void service_impls_should_be_annotated_with_Service() {
    classes().that().haveSimpleNameEndingWith("ServiceImpl")
        .should().beAnnotatedWith(Service.class)
        .check(classes);
}

@Test
void no_class_should_depend_on_implementation_package() {
    noClasses().that().resideOutsideOfPackage("..impl..")
        .should().dependOnClassesThat()
        .resideInAPackage("..impl..")
        .check(classes);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

其他推荐工具:

工具 用途
Spotless 代码格式化(支持 Google/Palantir/AOSP 风格)
jqwik 基于属性的测试(Property-Based Testing)
OWASP Dependency-Check 依赖漏洞扫描
JaCoCo 代码覆盖率报告(集成 SonarQube)

# 23.代码审查清单

每次 Code Review 时,按以下清单逐项检查:

## 命名
- [ ] 类/方法/变量名称是否见名知意
- [ ] 不存在拼音、单字母、数字编号的变量名
- [ ] 布尔变量使用 is/has/can 前缀

## 格式
- [ ] 缩进统一(4空格),无 Tab 混杂
- [ ] 大括号 K&R 风格
- [ ] 单行不超过120字符

## 注释
- [ ] 注释解释"为什么"而非"做了什么"
- [ ] 公共 API 有完整的 Javadoc
- [ ] 无明显无意义注释(`// i++ 自增`)

## 逻辑
- [ ] if 嵌套不超过 3 层
- [ ] 方法体不超过 80 行
- [ ] 无重复代码块(DRY)
- [ ] 异常正确捕获和处理,无空 catch 块

## 健壮性
- [ ] 入参有 null 校验
- [ ] 集合返回空集合而非 null
- [ ] 数据库查询有 LIMIT
- [ ] 敏感信息无硬编码
- [ ] 可变对象做了防御性拷贝(Date、集合等)

## 现代 Java
- [ ] 纯数据类优先考虑 Record(Java 14+)
- [ ] 有限子类层次用 Sealed Class(Java 17+)
- [ ] instanceof 用了模式匹配简化(Java 16+)
- [ ] 复杂 switch 用 switch 表达式(Java 14+)
- [ ] Stream 操作链 > 2 步才用 Stream

## 性能
- [ ] 循环中无数据库/RPC 调用
- [ ] 循环中无 `new SimpleDateFormat()` 或 `Pattern.compile()`
- [ ] 集合初始化指定了合理容量
- [ ] 缓存有大小上限和过期时间

## 测试
- [ ] 核心逻辑有单元测试
- [ ] 正向和异常路径都覆盖
- [ ] 测试方法命名清晰表达了测试意图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 24.常见陷阱速查

# 24.1 空指针陷阱

# 陷阱 正解
1 user.getName().equals("yc") → user.getName() 为 null "yc".equals(user.getName())
2 getOrders() 返回 null 返回 Collections.emptyList()
3 Map.get() 返回 null 直接拆箱 Long v = map.get(key); if (v != null) ...
4 Optional.get() 不检查 optional.orElseThrow() / optional.ifPresent()
5 Arrays.asList() 的元素修改影响数组 用 new ArrayList<>(Arrays.asList(...))

# 24.2 集合陷阱

# 陷阱 正解
1 Arrays.asList() 不可 add/remove new ArrayList<>(...)包装
2 for-each 中删除元素 → ConcurrentModificationException list.removeIf(...) 或 Iterator.remove()
3 list.contains(o) 依赖 equals,未重写则比较引用 重写 equals/hashCode
4 HashMap key 可变对象 → hash 变了找不到 key 用不可变对象(String、Integer、LocalDate)
5 Set 用自定义对象没重写 hashCode → 重复插入 重写 equals/hashCode

# 24.3 并发陷阱

# 陷阱 正解
1 HashMap 多线程 → 死循环(JDK7)/ 数据错乱 ConcurrentHashMap
2 SimpleDateFormat 多线程 → 数据错乱 DateTimeFormatter(线程安全)
3 ++count 不是原子操作 AtomicInteger.getAndIncrement()
4 double-checked locking 没用 volatile volatile + synchronized,或直接用枚举单例
5 Thread.stop() / suspend() 用 interrupt() + 协作式停止

# 24.4 性能陷阱

# 陷阱 正解
1 循环中 String += StringBuilder
2 循环中 Pattern.compile() / new SimpleDateFormat() 提取为 static final 常量
3 Exception.printStackTrace() 吞异常 logger.error(...) 记录完整堆栈
4 大对象 ThreadLocal 忘记 remove try { ... } finally { threadLocal.remove(); }
5 装箱类型循环中频繁用 == equals() 比较(或 -XX:+UnlockExperimentalVMOptions)
6 Stream 中抛检查异常 → try-catch 嵌套 提取为独立方法
上次更新: 2026/06/17, 09:06:19
C++编程代码规范指南
JavaScript编程规范指南

← C++编程代码规范指南 JavaScript编程规范指南→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式