跳转到内容

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 等判断
}