引言
好的编码规范不是教条,而是团队协作的润滑剂。一致的命名、合理的异常处理、不可变的设计、防御性的编码,这些习惯能让代码更健壮、更易维护。
一、命名规范
1.1 基本规则
| 类型 |
规范 |
示例 |
| 包名 |
全小写,点分隔 |
com.example.service |
| 类名 |
UpperCamelCase |
UserService, OrderProcessor |
| 方法名 |
lowerCamelCase |
findByName, calculateTotal |
| 变量名 |
lowerCamelCase |
userName, orderCount |
| 常量 |
UPPER_SNAKE_CASE |
MAX_RETRY_COUNT, DEFAULT_TIMEOUT |
| 泛型 |
单大写字母 |
T, E, K, V |
| 枚举 |
UpperCamelCase |
HttpStatus.OK |
1.2 方法命名动词表
| 动词 |
含义 |
示例 |
| get |
获取属性 |
getName() |
| set |
设置属性 |
setName(String) |
| is |
布尔判断 |
isActive() |
| has |
是否包含 |
hasPermission() |
| can |
能力判断 |
canExecute() |
| find |
查询(可能为空) |
findById() |
| list |
查询列表 |
listByStatus() |
| count |
计数 |
countByRole() |
| create |
创建 |
createOrder() |
| update |
更新 |
updateStatus() |
| delete |
删除 |
deleteById() |
| save |
保存(新建或更新) |
save(User) |
| validate |
验证 |
validateInput() |
| convert |
转换 |
convertToDTO() |
| build |
构建 |
buildResponse() |
| compute |
计算 |
computeHash() |
| resolve |
解析/解决 |
resolveConflict() |
| handle |
处理 |
handleException() |
| execute |
执行 |
executeTask() |
| apply |
应用 |
applyDiscount() |
1.3 避免的命名
int d;
String fn;
int elapsedTimeInDays;
String firstName;
String nameString;
int itemCountInt;
String name;
int itemCount;
boolean flag;
boolean status;
boolean isValid;
boolean hasPermission;
boolean canRetry;
String name1, name2;
String originalName;
String modifiedName;
二、异常处理
2.1 异常分类
Throwable
├── Error(不应捕获)
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── InternalError
└── Exception
├── 受检异常(Checked Exception)→ 必须处理
│ ├── IOException
│ ├── SQLException
│ └── InterruptedException
└── 非受检异常(RuntimeException)→ 可选处理
├── NullPointerException
├── IllegalArgumentException
├── IllegalStateException
└── IndexOutOfBoundsException
2.2 异常处理原则
try {
doSomething();
} catch (Exception e) {
}
try {
doSomething();
} catch (Exception e) {
e.printStackTrace();
}
try {
doSomething();
} catch (IOException e) {
log.error("Failed to read file: {}", filePath, e);
throw new BusinessException("File read failed", e);
}
try {
doSomething();
} catch (Exception e) {
log.error("Error", e);
}
try {
doSomething();
} catch (FileNotFoundException e) {
log.warn("File not found: {}", filePath);
return defaultValue;
} catch (IOException e) {
log.error("IO error reading file: {}", filePath, e);
throw new BusinessException("File read failed", e);
}
2.3 自定义异常
public class BusinessException extends RuntimeException {
private final String errorCode;
public BusinessException(String message) {
super(message);
this.errorCode = "GENERIC_ERROR";
}
public BusinessException(String errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public BusinessException(String errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
public String getErrorCode() {
return errorCode;
}
}
if (balance < amount) {
throw new BusinessException("INSUFFICIENT_BALANCE",
"Insufficient balance: " + balance + " < " + amount);
}
2.4 try-with-resources
try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
}
}
public class TempFile implements AutoCloseable {
private final Path path;
public TempFile(String prefix) throws IOException {
this.path = Files.createTempFile(prefix, ".tmp");
}
public Path getPath() { return path; }
@Override
public void close() {
try {
Files.deleteIfExists(path);
} catch (IOException e) {
}
}
}
try (TempFile temp = new TempFile("data")) {
Files.writeString(temp.getPath(), content);
processFile(temp.getPath());
}
2.5 异常链
public Data fetchData() {
try {
return readFromCache();
} catch (CacheException e) {
throw new BusinessException("CACHE_ERROR", "Failed to read cache", e);
}
}
catch (CacheException e) {
throw new BusinessException("Cache failed");
}
三、不可变对象
3.1 为什么不可变
不可变对象的好处:
├── 线程安全:无需同步
├── 可缓存:hashCode 可预计算
├── 可共享:无需防御性复制
├── 可靠:创建后状态不变
└── 简单:减少状态管理的复杂度
Java 中的不可变示例:
├── String
├── Integer, Long 等包装类
├── BigDecimal
├── LocalDate, LocalDateTime
└── ImmutableList (Guava)
3.2 设计不可变类
public final class Money {
private final BigDecimal amount;
private final String currency;
public Money(BigDecimal amount, String currency) {
this.amount = amount;
this.currency = Objects.requireNonNull(currency, "currency must not be null");
}
public BigDecimal getAmount() { return amount; }
public String getCurrency() { return currency; }
public Money add(Money other) {
if (!this.currency.equals(other.currency)) {
throw new IllegalArgumentException("Currency mismatch");
}
return new Money(this.amount.add(other.amount), this.currency);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Money)) return false;
Money money = (Money) o;
return amount.equals(money.amount) && currency.equals(money.currency);
}
@Override
public int hashCode() {
return Objects.hash(amount, currency);
}
@Override
public String toString() {
return amount + " " + currency;
}
}
3.3 Record 实现不可变(Java 16+)
public record Money(BigDecimal amount, String currency) {
public Money {
Objects.requireNonNull(currency, "currency must not be null");
if (amount.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Amount must be non-negative");
}
}
public Money add(Money other) {
if (!this.currency.equals(other.currency)) {
throw new IllegalArgumentException("Currency mismatch");
}
return new Money(this.amount.add(other.amount), this.currency);
}
}
3.4 集合不可变
List<String> list = List.of("a", "b", "c");
Set<String> set = Set.of("a", "b", "c");
Map<String, Integer> map = Map.of("a", 1, "b", 2);
list.add("d");
List<String> immutable = Collections.unmodifiableList(mutable);
List<String> copy = List.copyOf(mutable);
四、防御性编程
4.1 参数校验
public User createUser(String name, int age, String email) {
Objects.requireNonNull(name, "name must not be null");
Objects.requireNonNull(email, "email must not be null");
if (name.isBlank()) {
throw new IllegalArgumentException("name must not be blank");
}
if (age < 0 || age > 150) {
throw new IllegalArgumentException("age must be between 0 and 150");
}
if (!email.contains("@")) {
throw new IllegalArgumentException("invalid email format");
}
return new User(name, age, email);
}
4.2 防御性复制
public class Order {
private final List<Item> items;
public Order(List<Item> items) {
this.items = new ArrayList<>(items);
}
public List<Item> getItems() {
return Collections.unmodifiableList(items);
}
}
4.3 返回空集合而非 null
public List<Order> getOrdersByUser(String userId) {
List<Order> orders = orderDao.findByUser(userId);
return orders.isEmpty() ? null : orders;
}
public List<Order> getOrdersByUser(String userId) {
List<Order> orders = orderDao.findByUser(userId);
return orders;
}
public Optional<User> findById(String id) {
return Optional.ofNullable(userDao.selectById(id));
}
4.4 快速失败(Fail-Fast)
public void processOrder(Order order) {
Objects.requireNonNull(order, "order must not be null");
if (order.getItems().isEmpty()) {
throw new IllegalArgumentException("order must have at least one item");
}
if (order.getTotal().compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("order total must be positive");
}
validateInventory(order);
reserveItems(order);
processPayment(order);
}
4.5 前置条件工具
Preconditions.checkNotNull(name, "name must not be null");
Preconditions.checkArgument(age >= 0, "age must be non-negative, got: %s", age);
Preconditions.checkState(isInitialized, "service not initialized");
Objects.requireNonNull(name, "name must not be null");
public class Validate {
public static void isTrue(boolean expression, String message) {
if (!expression) {
throw new IllegalArgumentException(message);
}
}
public static void notEmpty(String value, String message) {
if (value == null || value.isBlank()) {
throw new IllegalArgumentException(message);
}
}
public static <T> void notEmpty(Collection<T> collection, String message) {
if (collection == null || collection.isEmpty()) {
throw new IllegalArgumentException(message);
}
}
}
五、代码设计原则
5.1 SOLID 原则速查
| 原则 |
含义 |
简述 |
| S - 单一职责 |
一个类只有一个变化原因 |
小而专注 |
| O - 开闭原则 |
对扩展开放,对修改关闭 |
策略/模板模式 |
| L - 里氏替换 |
子类可以替换父类 |
不要破坏契约 |
| I - 接口隔离 |
接口要小而专 |
不要胖接口 |
| D - 依赖倒置 |
依赖抽象不依赖实现 |
面向接口编程 |
5.2 方法设计
public void process() {
readData();
String line = reader.readLine();
validateData();
saveData();
}
public void process() {
Data data = readData();
validateData(data);
saveData(data);
}
public User create(String name, int age, String email, String phone, String address) { }
public User create(CreateUserRequest request) { }
sendEmail(to, subject, body, true);
sendEmail(to, subject, body, EmailType.HTML);
5.3 注释原则
i++;
String name = user.getName();
int index = Collections.binarySearch(sortedList, target);
public Optional<User> findById(String userId) { ... }
总结
| 要点 |
建议 |
| 命名 |
有意义、可读、一致 |
| 异常 |
不吞掉、不丢失、具体捕获 |
| 不可变 |
优先设计不可变类 |
| 防御性 |
校验参数、防御性复制、返回空集合 |
| 方法 |
短小、单一职责、参数少 |
| 注释 |
解释 Why,不解释 What |
| 快速失败 |
尽早暴露问题 |
所有评论(0)