Java开发规范
Java 通用编码规范(阿里巴巴规约、命名、注释)
- [Requirement] 类名使用大驼峰(UpperCamelCase):
UserService、OrderRepository;抽象类以Abstract开头,异常类以Exception结尾,测试类以Test结尾。 - [Requirement] 方法名、变量名、参数名使用小驼峰(lowerCamelCase):
getUserById、orderId。 - [Requirement] 常量全大写下划线:
MAX_RETRY_COUNT;包名全小写,禁止下划线与大写字母,按域名倒序:com.company.project.module。 - [Standard] 布尔变量/方法禁止用
is前缀命名字段(如isDeleted),应为deleted,避免序列化与框架反射冲突;布尔 getter 用isDeleted()。 - [Standard] 数组类型声明紧跟类型:
String[] args,禁止String args[]。 - [Standard] 接口名不加
I前缀(UserService而非IUserService);实现类可加Impl后缀(UserServiceImpl)。 - [Standard] 泛型类型参数用单个大写字母:
T(类型)、E(元素)、K/V(键值)、R(返回)。 - [Caution] 禁止使用拼音、英文缩写不清晰的命名(
dj、hz);禁止使用l(小写 L)、O(大写 O)作为变量名,易与数字混淆。 - [Caution] 禁止在不同上下文复用同名变量含义,禁止用
data1、data2、tmp这类无意义命名。
// 类与方法命名
public class UserService {
private static final int MAX_PAGE_SIZE = 100;
public User getUserById(Long userId) {
boolean deleted = false;
String[] userNames = {"alice", "bob"};
// ...
}
}
// 异常类
public class UserNotFoundException extends RuntimeException {
}
// 接口与实现
public interface OrderRepository {
Order findById(Long id);
}
@Repository
public class OrderRepositoryImpl implements OrderRepository {
}
// 泛型
public <T> Result<T> success(T data) {
return new Result<>(0, "success", data);
}// 反模式:命名不规范
public class userService { // 类名小驼峰
public void GetUserById() { } // 方法名大驼峰
static final int maxRetry = 3; // 常量未大写
boolean isDeleted; // 布尔字段用 is 前缀
String args[]; // 数组声明位置错误
int l = 0; // 变量名易混淆
}
// 反模式:无意义命名
String data1, data2, tmp;- [Requirement] 类、接口、public 方法必须有 Javadoc 注释,说明用途、参数、返回值与抛出异常。
- [Requirement] 类注释必须包含作者与创建日期:
@author、@date。 - [Standard] 方法注释描述”做什么”而非”怎么做”,实现细节用行内注释。
- [Standard] 行内注释
//与代码间空 2 空格,与注释内容间空 1 空格;禁止无意义注释(如i++ // i 加 1)。 - [Standard] 特殊标记注释统一格式:
TODO、FIXME、XXX,后跟描述与负责人,例如// TODO(zouhs): 待补充缓存逻辑。 - [Default] 复杂业务逻辑、算法、边界条件必须注释说明原因(Why),而非重复代码(What)。
- [Caution] 禁止注释掉的代码长期存在,必须删除;注释与代码不一致时,以代码为准并修正注释。
/**
* 用户服务,提供用户的增删改查与权限校验。
*
* @author zouhs
* @date 2026-10-14
*/
@Service
public class UserService {
/**
* 根据用户 ID 查询用户,不存在时返回 null。
*
* @param userId 用户 ID,必须大于 0
* @return 用户实体,不存在返回 null
* @throws IllegalArgumentException 当 userId 非法时抛出
*/
public User getUserById(Long userId) {
if (userId == null || userId <= 0) {
throw new IllegalArgumentException("userId must be positive");
}
// 优先查缓存,未命中再查库
User cached = cache.get(userId);
return cached != null ? cached : userRepository.findById(userId);
}
}// 反模式:注释重复代码、无意义
int count = 0;
count++; // count 加 1
// 反模式:被注释的代码长期存在
// public void oldMethod() {
// ...
// }
// 反模式:public 方法无 Javadoc
public void processOrder() {
// 处理订单(描述了 What 而非 Why,且无业务背景)
}- [Requirement] 集合初始化时指定初始容量:
new ArrayList<>(16)、new HashMap<>(16),避免频繁扩容。 - [Requirement] 遍历集合时禁止使用
fori修改集合结构(add/remove),必须用Iterator或removeIf。 - [Requirement] 集合判空用
CollectionUtils.isEmpty()或CollUtil.isEmpty(),禁止用list.size() == 0。 - [Standard] 优先使用接口声明变量:
List<String> list = new ArrayList<>(),而非ArrayList<String> list。 - [Standard]
HashMap的 key 为自定义对象时必须重写hashCode与equals;优先使用String、Integer等不可变类型作 key。 - [Standard] 集合转数组用
list.toArray(new String[0])(Java 8)或list.toArray(String[]::new)(Java 11+)。 - [Default] 使用
stream()时注意性能:简单循环优先用 for 或增强 for,复杂聚合/过滤才用 Stream;避免在 Stream 中修改外部状态。 - [Caution]
Arrays.asList()返回的列表不可变且不支持add/remove,禁止直接修改;需修改需new ArrayList<>(Arrays.asList(...))。 - [Caution] 禁止在 foreach 中调用
list.remove(),会抛ConcurrentModificationException。
// 初始容量
Map<String, User> userMap = new HashMap<>(16);
List<User> users = new ArrayList<>(16);
// 安全删除
users.removeIf(user -> user.getStatus() == UserStatus.DISABLED);
// 或使用 Iterator
Iterator<User> it = users.iterator();
while (it.hasNext()) {
User u = it.next();
if (u.getStatus() == UserStatus.DISABLED) {
it.remove();
}
}
// 集合判空
if (CollUtil.isEmpty(users)) {
return Collections.emptyList();
}
// 转数组
String[] arr = users.stream().map(User::getName).toArray(String[]::new);// 反模式:foreach 中 remove,抛 ConcurrentModificationException
for (User u : users) {
if (u.getStatus() == UserStatus.DISABLED) {
users.remove(u);
}
}
// 反模式:用 size 判空
if (users.size() == 0) { ... }
// 反模式:Arrays.asList 后修改
List<String> list = Arrays.asList("a", "b");
list.add("c"); // 抛 UnsupportedOperationException
// 反模式:未指定初始容量
List<User> users = new ArrayList<>(); // 大量元素时频繁扩容- [Requirement] 线程资源必须通过线程池提供,禁止显式
new Thread();线程池不允许用Executors创建,必须用ThreadPoolExecutor显式指定参数。 - [Requirement] 线程池必须设置有界队列与拒绝策略,
corePoolSize、maximumPoolSize、keepAliveTime、队列容量根据业务压测确定。 - [Requirement]
SimpleDateFormat非线程安全,多线程场景必须用DateTimeFormatter(Java 8+)或ThreadLocal<SimpleDateFormat>。 - [Standard]
synchronized锁代码块而非整个方法,锁粒度尽可能小;锁对象必须是private final。 - [Standard] 优先使用
java.util.concurrent并发工具(ConcurrentHashMap、AtomicLong、CountDownLatch),减少手动锁。 - [Standard]
volatile仅用于一写多读的可见性场景,不能保证原子性;计数用AtomicInteger/Long。 - [Default] 线程池线程命名必须有意义前缀(
user-task-pool-),便于排查问题;通过ThreadFactory设置。 - [Caution] 锁内禁止调用远程接口、数据库操作等耗时阻塞操作,避免长时间持锁。
- [Caution]
ThreadLocal使用后必须remove(),防止内存泄漏与线程复用导致的数据串扰。
// 正确:显式线程池
private static final ThreadPoolExecutor USER_TASK_POOL = new ThreadPoolExecutor(
4, 8, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000),
new ThreadFactoryBuilder().setNameFormat("user-task-pool-%d").build(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
// 正确:并发计数
private final AtomicLong counter = new AtomicLong(0);
public long increment() {
return counter.incrementAndGet();
}
// 正确:锁小粒度
private final Object lock = new Object();
public void update(User user) {
synchronized (lock) {
userRepository.update(user);
}
}
// 正确:ThreadLocal 使用后清理
private static final ThreadLocal<SimpleDateFormat> SDF =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
try {
String date = SDF.get().format(new Date());
} finally {
SDF.remove();
}// 反模式:Executors 无界队列,可能 OOM
ExecutorService pool = Executors.newFixedThreadPool(10);
// 反模式:SimpleDateFormat 共享
private static final SimpleDateFormat SDF = new SimpleDateFormat(); // 线程不安全
// 反模式:锁内远程调用
synchronized (this) {
remoteService.callSlowApi(); // 长时间持锁,阻塞其他线程
}
// 反模式:ThreadLocal 未 remove
ThreadLocal<User> currentUser = new ThreadLocal<>();
currentUser.set(user);
// 用完未 remove,线程池复用导致数据串扰- [Requirement] 禁止捕获
Exception或Throwable后吞掉(空 catch),至少记录日志或重新抛出。 - [Requirement] 自定义业务异常继承
RuntimeException,命名以Exception结尾,携带错误码与消息。 - [Requirement] 方法签名上禁止
throws Exception,必须抛出具体异常类型;不要用异常控制正常业务流程。 - [Standard]
finally块中禁止return,会覆盖 try 块的返回值与异常;资源关闭用 try-with-resources。 - [Standard] 捕获异常后记录日志必须包含完整堆栈
log.error("msg", e),禁止只log.error(e.getMessage())。 - [Standard] 远程调用、数据库操作必须捕获并区分异常类型,做重试、降级或抛出业务异常。
- [Default] 对外暴露的接口统一用全局异常处理器转换为标准错误响应,禁止将堆栈信息返回给前端。
- [Caution] 禁止在循环中捕获异常后继续执行而不记录,会掩盖真实错误;禁止
catch后throw new RuntimeException(e.getMessage())丢失原始堆栈。
// 自定义业务异常
public class BizException extends RuntimeException {
private final int code;
public BizException(int code, String message) {
super(message);
this.code = code;
}
public int getCode() {
return code;
}
}
// try-with-resources 自动关闭资源
public String readFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
// 远程调用异常处理
public User getUser(Long id) {
try {
return userClient.getById(id);
} catch (FeignException e) {
log.error("调用用户服务失败, userId={}", id, e);
throw new BizException(ErrorCode.USER_SERVICE_ERROR, "用户服务不可用");
}
}// 反模式:吞掉异常
try {
doSomething();
} catch (Exception e) {
// 空 catch,掩盖错误
}
// 反模式:只记录消息不记录堆栈
try {
doSomething();
} catch (Exception e) {
log.error(e.getMessage()); // 丢失堆栈
}
// 反模式:finally 中 return
public int calc() {
try {
return 1;
} finally {
return 2; // 永远返回 2,覆盖 try 的结果
}
}
// 反模式:用异常控制流程
try {
Integer.parseInt(str);
} catch (NumberFormatException e) {
return false; // 应用 StringUtils.isNumeric 等判断
}