那天晚上11点,微信群里炸了锅。生产环境又出事了,这次是一个看似简单的用户信息查询接口,在高并发下直接把数据库连接池干爆了。排查到最后,问题竟然出在一个看起来人畜无害的代码片段上:
// 某位同学写的"优雅"代码
public List<User> getUsersByIds(List<Long> userIds) {
List<User> users = new ArrayList<>();
for (Long userId : userIds) {
User user = userMapper.selectById(userId);
if (user != null) {
users.add(user);
}
}
return users;
}
看出问题了吗?每次循环都要执行一次数据库查询,传入1000个用户ID,就是1000次SQL。这种N+1问题在新人代码里简直是家常便饭。
在腾讯待了几年,我深深体会到一件事:代码规范绝不是为了让代码"好看",而是为了在高并发、大流量的业务场景下保命。
腾讯内部有一套严格的Java代码规范,核心思想可以总结为"防患于未然"。每一条规范背后,都对应着一个血淋淋的生产事故。
比如刚才那个例子,如果严格按照腾讯的数据库操作规范:
// 腾讯推荐的写法
public List<User> getUsersByIds(List<Long> userIds) {
if (CollectionUtils.isEmpty(userIds)) {
return Collections.emptyList();
}
// 批量查询,一次SQL解决
return userMapper.selectBatchIds(userIds);
}
一行代码解决的事情,为啥要写一个循环?这就是规范的力量。
最经典的就是Optional的使用。我见过太多同学写出这样的代码:
// 危险写法
String userName = user.getName().toUpperCase();
腾讯的规范要求:任何可能为null的对象调用,必须先判空。更进一步,推荐使用Optional:
// 安全写法
String userName = Optional.ofNullable(user.getName())
.map(String::toUpperCase)
.orElse("UNKNOWN");
这不是为了显摆函数式编程有多酷,而是为了在编译期就把空指针问题扼杀在摇篮里。
还有一个让无数人掉坑的地方:集合的contains操作。
// 性能杀手
List<String> blackList = Arrays.asList("user1", "user2", ...); // 假设有10000个元素
if (blackList.contains(currentUser)) {
// 每次contains都是O(n)时间复杂度
}
腾讯规范明确规定:超过100个元素的集合查找,必须使用Set或Map。
// 正确姿势
Set<String> blackListSet = new HashSet<>(blackList);
if (blackListSet.contains(currentUser)) {
// O(1)时间复杂度
}
你可能觉得这些都是基础知识,但我敢打赌,十个项目里有八个都有这样的问题。
腾讯最牛的地方在于,这些规范不是写在文档里供人膜拜的,而是通过Checkstyle、PMD、SpotBugs等工具强制执行。代码提交前,必须通过静态检查,违反规范的代码根本推不上去。
我印象最深的是一条关于魔法数字的规范:
// 禁止写法
if (user.getStatus() == ) {
// 1是什么意思?激活?删除?封禁?
}
// 推荐写法
private static final int USER_STATUS_ACTIVE = ;
if (user.getStatus() == USER_STATUS_ACTIVE) {
// 一目了然
}
这看起来是小事,但当你在凌晨2点调试线上问题时,看到一堆莫名其妙的数字,你就知道规范的珍贵了。
腾讯的Java规范有个核心理念:代码是写给人看的,顺便让机器执行。
每一行代码都可能被无数人阅读、修改、维护。一个看似聪明的写法,可能会让后来的维护者抓狂三天三夜。
最让我佩服的是腾讯对异常处理的要求:永远不要吞掉异常。
// 绝对禁止
try {
riskyOperation();
} catch (Exception e) {
// 静默吞掉异常,后果自负
}
// 正确做法
try {
riskyOperation();
} catch (Exception e) {
log.error("操作失败,用户ID: {}", userId, e);
// 根据业务场景决定是重试、降级还是直接抛出
throw new BusinessException("用户操作失败", e);
}
这不是矫情,而是血的教训。线上出了问题,没有日志就是瞎子摸象。
我见过太多项目,开始时为了快速迭代忽视规范,后来技术债越欠越多,最后重构的成本比重写还高。
腾讯的代码规范看似严苛,实际上是在用短期的"不方便"换取长期的"高效率"。当你的项目从千行代码成长到百万行代码时,你会感谢当初对规范的坚持。
真正的高手,从来不是写出多么炫技的代码,而是写出让团队都能理解和维护的代码。这才是万行代码零bug的真正秘密。