关于 java-dev
java-dev 是面向 Java 开发者的技能,依据 Alibaba Coding Guidelines 支持代码编写、审查和重构,涵盖风格、安全、并发、数据库与测试规范。
主要功能
- 01Java 命名和代码结构规范
- 02异常处理与并发指导
- 03数据库设计和 SQL 安全实践
- 04安全与输入验证检查
- 05JUnit 5 和 Mockito 测试指导
- 06代码审查清单
适用场景
- 01为新 Java 服务应用统一规范
- 02检查 SQL 注入风险和查询实践
- 03规划线程池及线程安全代码
- 04在代码审查中检查测试与安全
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ story-has-you/ skills --skill java-dev安装后在 Claude Code 中输入/java-dev确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/coding-standards.mdconcurrency.mddatabase.mddesign.mdexception-logging.mdnaming-conventions.mdsecurity.mdtesting.md详细介绍
Java 开发 - 阿里巴巴编码指南
概述
本技能提供全面的 Java 开发指导,依据《阿里巴巴 Java 开发手册》(嵩山版)。它确保所有 Java 代码都遵循行业最佳实践,涵盖命名规范、编码标准、并发、异常处理、数据库设计、安全、测试和架构设计。
核心原则
编写 Java 代码时,始终遵循以下基本原则:
- 代码可读性:编写易于理解和维护的代码
- 一致性:遵循一致的命名和格式规范
- 安全第一:防止 NPE、SQL 注入和并发问题等常见陷阱
- 关注性能:考虑设计决策对性能的影响
- 测试覆盖率:确保关键代码具有足够的单元测试覆盖率
快速参考
命名规范
- 类:UpperCamelCase(例如,
UserService、OrderController) - 方法/变量:lowerCamelCase(例如,
getUserById、userName) - 常量:UPPER_SNAKE_CASE(例如,
MAX_COUNT、DEFAULT_SIZE) - 包:使用小写,优先使用单个单词(例如,
com.company.module)
常见模式
- 抽象类:使用
Abstract*或Base*前缀 - 异常类:使用
*Exception后缀 - 测试类:使用
*Test后缀 - 服务实现类:使用
*Impl后缀 - 布尔变量:POJO 类中不使用
is前缀 - DAO 方法:
get*(单个)、list*(多个)、count*、save*、remove*、update*
关键规则
- ❌ 绝不在代码中直接使用魔法数字
- ❌ 绝不捕获异常却不进行处理
- ❌ 绝不使用
==比较包装类型(请使用equals()) - ❌ 绝不直接创建线程(请使用线程池)
- ❌ 绝不在 SQL 查询中使用
SELECT * - ✅ 始终使用参数化查询,防止 SQL 注入
- ✅ 已知集合大小时,始终指定初始容量
- ✅ 始终在
finally块中关闭资源,或使用 try-with-resources - ✅ 始终验证外部输入
工作流
1. 编写代码前
查看详细指南:
- 命名规则 → 请参阅 naming-conventions.md
- 编码标准 → 请参阅 coding-standards.md
- 并发 → 请参阅 concurrency.md
- 数据库设计 → 请参阅 database.md
- 安全 → 请参阅 security.md
- 测试 → 请参阅 testing.md
- 设计模式 → 请参阅 design.md
2. 编写代码
编写代码时应用以下检查:
命名
- 类名使用 UpperCamelCase
- 方法名/变量名使用 lowerCamelCase
- 常量使用 UPPER_SNAKE_CASE
- 使用有意义的英文名称(不使用拼音)
代码结构
- 方法少于 80 行
- 每个类/方法只承担单一职责
- 使用恰当的访问修饰符(默认使用 private)
- 重写方法时使用
@Override
需要避免的常见陷阱
// ❌ Wrong: Magic numbers
if (status == 1) { ... }
// ✅ Correct: Named constants
private static final int STATUS_ACTIVE = 1;
if (status == STATUS_ACTIVE) { ... }
// ❌ Wrong: Comparing wrapper types with ==
Integer a = 128;
Integer b = 128;
if (a == b) { ... } // May fail!
// ✅ Correct: Use equals()
if (a.equals(b)) { ... }
// ❌ Wrong: Empty catch block
try {
doSomething();
} catch (Exception e) {
// Silent failure
}
// ✅ Correct: Handle or rethrow
try {
doSomething();
} catch (Exception e) {
logger.error("Failed to do something", e);
throw new BusinessException("Operation failed", e);
}
// ❌ Wrong: Creating threads directly
new Thread(() -> doWork()).start();
// ✅ Correct: Use thread pool
ExecutorService executor = new ThreadPoolExecutor(
corePoolSize, maxPoolSize, keepAliveTime,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(),
new ThreadFactoryBuilder().setNameFormat("worker-%d").build()
);
executor.submit(() -> doWork());
3. 数据库操作
表设计
- 表名:使用小写字母和下划线(例如,
user_order) - 必需字段:
id、create_time、update_time - 布尔字段:使用
is_*前缀(例如,is_deleted) - ID 使用
BIGINT UNSIGNED - 金额使用
DECIMAL(绝不使用FLOAT或DOUBLE)
SQL 最佳实践
// ✅ Correct: Parameterized query
String sql = "SELECT id, user_name, email FROM user WHERE id = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setLong(1, userId);
// ✅ Correct: MyBatis parameter binding
@Select("SELECT * FROM user WHERE user_name = #{userName}")
User selectByUserName(@Param("userName") String userName);
// ❌ Wrong: String concatenation (SQL injection risk!)
String sql = "SELECT * FROM user WHERE user_name = '" + userName + "'";
4. 异常处理
异常层级
- 使用具体的异常类型
- 可恢复错误使用受检异常
- 编程错误使用非受检异常
- 始终在异常消息中包含上下文信息
// ✅ Correct exception handling
public User getUserById(Long userId) {
if (userId == null) {
throw new IllegalArgumentException("userId cannot be null");
}
User user = userDao.selectById(userId);
if (user == null) {
throw new NotFoundException("User not found: " + userId);
}
return user;
}
// ✅ Correct logging with exception
try {
processOrder(order);
} catch (Exception e) {
logger.error("Failed to process order, orderId: {}", order.getId(), e);
throw new BusinessException("订单处理失败", e);
}
5. 并发
线程安全规则
- 使用
ThreadPoolExecutor,而不是Executors - 为线程命名,以便调试
- 使用
volatile保证可见性,使用AtomicXxx执行原子操作 - 避免在多线程代码中使用
SimpleDateFormat(请使用DateTimeFormatter) - 清理
ThreadLocal变量
// ✅ Correct: Thread pool with proper configuration
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10, // corePoolSize
20, // maximumPoolSize
60L, // keepAliveTime
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
new ThreadFactoryBuilder().setNameFormat("order-processor-%d").build(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
// ✅ Correct: ThreadLocal cleanup
private static final ThreadLocal<User> USER_CONTEXT = new ThreadLocal<>();
public void processRequest() {
try {
USER_CONTEXT.set(getCurrentUser());
// Process request
} finally {
USER_CONTEXT.remove(); // Critical: prevent memory leak
}
}
6. 安全
输入验证
- 验证所有外部输入
- 使用参数化查询(绝不进行字符串拼接)
- 对 HTML 输出进行清理,以防止 XSS
- 实施 CSRF 防护
- 在日志中屏蔽敏感数据
// ✅ Correct: Input validation
public void createUser(UserCreateRequest request) {
if (StringUtils.isBlank(request.getUserName())) {
throw new ValidationException("用户名不能为空");
}
if (!ValidationUtils.isValidMobile(request.getMobile())) {
throw new ValidationException("手机号格式不正确");
}
// Process...
}
// ✅ Correct: Sensitive data masking
logger.info("User login, mobile: {}", maskMobile(user.getMobile()));
7. 单元测试
测试标准
- 测试类命名:
*Test - 测试方法命名:
test* - 覆盖率目标:语句覆盖率至少为 70%
- 使用 JUnit 5 + Mockito
- 遵循 BCDE 原则(边界、正确、设计、错误)
@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
@Mock
private UserDao userDao;
@InjectMocks
private UserService userService;
@Test
@DisplayName("根据ID获取用户 - 正常情况")
public void testGetUserById_Success() {
// Given
Long userId = 1L;
User mockUser = new User();
mockUser.setId(userId);
mockUser.setUserName("test");
when(userDao.selectById(userId)).thenReturn(mockUser);
// When
User result = userService.getUserById(userId);
// Then
assertNotNull(result);
assertEquals(userId, result.getId());
verify(userDao, times(1)).selectById(userId);
}
@Test
@DisplayName("根据ID获取用户 - 参数为null")
public void testGetUserById_NullParameter() {
assertThrows(IllegalArgumentException.class, () -> {
userService.getUserById(null);
});
}
}
代码审查清单
审查 Java 代码时,请确认:
命名与风格
- 类名使用 UpperCamelCase
- 方法名和变量名使用 lowerCamelCase
- 常量使用 UPPER_SNAKE_CASE
- 代码中没有魔法数字
- 使用有意义的英文名称(不使用拼音)
代码质量
- 方法不超过 80 行
- 遵循单一职责原则
- 使用适当的访问修饰符
- 没有重复代码
- 妥善处理异常
安全性
- 没有 NPE 风险(必要时进行空值检查)
- 使用
equals()而非==比较包装类型 - 妥善关闭资源(使用 try-with-resources 或 finally)
- 在并发环境中使用时确保线程安全
- 对外部数据进行输入验证
数据库
- 使用参数化查询(没有 SQL 注入风险)
- 仅选择指定列(不使用
SELECT *) - 定义适当的索引
- 事务边界正确
性能
- 已知集合大小时指定初始容量
- 在循环中使用
StringBuilder进行字符串拼接 - 选择适当的数据结构
- 循环中没有不必要的对象创建
测试
- 为新增代码编写单元测试
- 覆盖边界情况
- 测试异常情况
- 妥善模拟依赖项
参考文档
有关特定主题的详细指南,请参阅以下参考文档:
naming-conventions.md
类、方法、变量、包和领域模型的完整命名规则。
coding-standards.md
详细的编码标准,包括常量、格式、面向对象编程规则、日期和时间处理、集合及控制语句。
concurrency.md
全面的并发指南,涵盖线程池、锁、volatile、并发集合和常见模式。
exception-logging.md
使用 SLF4J 的异常处理最佳实践和日志标准。
database.md
MySQL 数据库设计规则、索引策略、SQL 优化和 ORM 映射约定。
security.md
安全指南,涵盖输入验证、SQL 注入防护、XSS 防护、CSRF 防御、加密和敏感数据处理。
testing.md
单元测试标准、框架(JUnit 5、Mockito)、覆盖率要求和测试模式。
design.md
设计原则、分层架构、领域模型、设计模式和 API 设计约定。
常见场景
场景 1:创建新的服务类
- 阅读 naming-conventions.md,了解服务命名规则
- 阅读 coding-standards.md,了解类结构
- 阅读 exception-logging.md,了解错误处理
- 按照上述模式实现
- 按照 testing.md 编写单元测试
场景 2:数据库表设计
- 阅读 database.md,了解表设计规则
- 确保包含必需字段:
id、create_time、update_time - 使用适当的数据类型(金钱使用 DECIMAL,ID 使用 BIGINT)
- 添加适当的索引
- 按照命名约定创建对应的 DO 类
场景 3:实现并发处理
- 阅读 concurrency.md,了解线程池配置
- 使用
ThreadPoolExecutor并设置适当的参数 - 为线程命名,以便调试
- 处理工作线程中的异常
- 清理 ThreadLocal 变量
场景 4:安全审查
- 阅读 security.md,查看安全检查清单
- 确认已进行输入验证
- 检查是否存在 SQL 注入漏洞
- 确保日志中的敏感数据已脱敏
- 验证身份验证和授权
与开发工作流集成
此技能可无缝融入开发流程:
- 开发期间:参考上述快速规则,并按需查阅详细指南
- 代码审查:使用检查清单确保符合要求
- 重构:应用指南改进现有代码
- 新成员入职:用作新团队成员的培训材料
总结
此技能确保所有 Java 代码均遵循 Alibaba 的行业标准编码指南。始终优先考虑:
- 可读性,而非炫技
- 安全性,而非便利性
- 可维护性,而非快速修补
- 标准,而非个人偏好
如有疑问,请查阅详细参考文档以获取具体指导。
评论
支持 Markdown