Java最佳实践案例
代码组织与结构
包命名规范
// 好的实践:倒置域名 + 项目/模块名 package com.example.project.service; package org.openapi.common.util; // 避免:无意义或过于简单的包名 package util; // 不推荐 package test; // 不推荐
单一切责原则(SRP)
// ❌ 坏实践:一个类承担太多职责
public class UserManager {
public void createUser() { /* ... */ }
public void sendEmail() { /* ... */ }
public void generateReport() { /* ... */ }
public void validateData() { /* ... */ }
}
// ✅ 好实践:每个类专注于单一职责
public class UserService {
public void createUser(User user) { /* ... */ }
}
public class EmailService {
public void sendWelcomeEmail(User user) { /* ... */ }
}
public class ReportService {
public Report generateUserReport(List<User> users) { /* ... */ }
}
public class UserValidator {
public boolean isValid(User user) { /* ... */ }
}
异常处理最佳实践
使用具体异常类型
// ❌ 坏实践:捕获过于宽泛的异常
try {
// some code
} catch (Exception e) {
logger.error("Error occurred", e);
throw new RuntimeException(e);
}
// ✅ 好实践:捕获具体异常
try {
// 文件操作
FileInputStream fis = new FileInputStream("file.txt");
} catch (FileNotFoundException e) {
logger.error("File not found", e);
throw new CustomFileNotFoundException("Configuration file missing", e);
} catch (IOException e) {
logger.error("IO error", e);
throw new CustomIOException("Failed to read file", e);
}
自定义异常
// ✅ 好实践:创建有意义的自定义异常
public class InsufficientBalanceException extends RuntimeException {
private final String accountId;
private final BigDecimal currentBalance;
private final BigDecimal requiredAmount;
public InsufficientBalanceException(String accountId,
BigDecimal currentBalance,
BigDecimal requiredAmount) {
super(String.format("Account %s has insufficient balance. Required: %s, Current: %s",
accountId, requiredAmount, currentBalance));
this.accountId = accountId;
this.currentBalance = currentBalance;
this.requiredAmount = requiredAmount;
}
// getters...
}
资源管理
Try-with-Resources
// ❌ 坏实践:手动管理资源
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
String line = reader.readLine();
} catch (IOException e) {
logger.error("Error reading file", e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
logger.error("Error closing reader", e);
}
}
}
// ✅ 好实践:使用try-with-resources自动关闭
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
FileWriter writer = new FileWriter("output.txt")) {
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.write("\n");
}
} catch (IOException e) {
logger.error("Error processing file", e);
}
集合与泛型
使用泛型增强类型安全
// ❌ 坏实践:使用原始类型
List list = new ArrayList();
list.add("string");
list.add(123);
String item = (String) list.get(0); // 需要强制类型转换,可能导致ClassCastException
// ✅ 好实践:使用泛型
List<String> stringList = new ArrayList<>();
stringList.add("string");
// stringList.add(123); // 编译错误,类型安全
String item = stringList.get(0); // 无需强制类型转换
// 使用通配符提高灵活性
public void processList(List<? extends Number> numbers) {
for (Number number : numbers) {
System.out.println(number.doubleValue());
}
}
不可变集合
// ✅ 好实践:使用不可变集合
import java.util.Collections;
import java.util.List;
public class Constants {
public static final List<String> SUPPORTED_LANGUAGES =
Collections.unmodifiableList(Arrays.asList("en", "zh", "ja", "ko"));
// Java 9+ 使用of方法
public static final List<String> SUPPORTED_LANGUAGES_V2 =
List.of("en", "zh", "ja", "ko");
public static final Map<String, String> COUNTRY_CODES =
Map.of(
"US", "United States",
"CN", "China",
"JP", "Japan"
);
}
并发编程
使用并发工具类
// ❌ 坏实践:使用synchronized在集合上
public class Counter {
private final Map<String, Integer> countMap = new HashMap<>();
public synchronized void increment(String key) {
countMap.merge(key, 1, Integer::sum);
}
}
// ✅ 好实践:使用ConcurrentHashMap
public class Counter {
private final ConcurrentHashMap<String, AtomicInteger> countMap = new ConcurrentHashMap<>();
public void increment(String key) {
countMap.computeIfAbsent(key, k -> new AtomicInteger()).incrementAndGet();
}
public int getCount(String key) {
return countMap.getOrDefault(key, new AtomicInteger()).get();
}
}
// 使用ExecutorService管理线程池
public class TaskExecutor {
private final ExecutorService executor = Executors.newFixedThreadPool(10);
public Future<String> submitTask(Callable<String> task) {
return executor.submit(task);
}
public void shutdown() {
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
避免线程安全问题
// ❌ 坏实践:SimpleDateFormat线程不安全
public class DateFormatter {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
public String format(Date date) {
return dateFormat.format(date); // 多线程环境下可能出错
}
}
// ✅ 好实践:使用线程安全的DateTimeFormatter
public class DateFormatter {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE;
public String format(LocalDate date) {
return date.format(FORMATTER); // 线程安全
}
}
性能优化
字符串操作优化
// ❌ 坏实践:频繁字符串拼接
String result = "";
for (int i = 0; i < 1000; i++) {
result += "Item " + i + ", "; // 每次循环创建新String对象
}
// ✅ 好实践:使用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append("Item ").append(i).append(", ");
}
String result = sb.toString();
懒加载优化
// ✅ 好实践:使用懒加载模式
public class DataLoader {
private volatile HeavyData heavyData;
private final ReentrantLock lock = new ReentrantLock();
public HeavyData getHeavyData() {
// 双重检查锁定
if (heavyData == null) {
lock.lock();
try {
if (heavyData == null) {
heavyData = loadHeavyData(); // 耗时操作
}
} finally {
lock.unlock();
}
}
return heavyData;
}
}
设计模式应用
工厂模式
// ✅ 好实践:使用工厂模式创建对象
public interface Notification {
void send(String message);
}
public class EmailNotification implements Notification {
@Override
public void send(String message) {
// 发送邮件
}
}
public class SMSNotification implements Notification {
@Override
public void send(String message) {
// 发送短信
}
}
public class NotificationFactory {
public static Notification createNotification(NotificationType type) {
return switch (type) {
case EMAIL -> new EmailNotification();
case SMS -> new SMSNotification();
default -> throw new IllegalArgumentException("Unknown notification type: " + type);
};
}
}
// 使用
Notification notification = NotificationFactory.createNotification(NotificationType.EMAIL);
notification.send("Your order has been confirmed!");
策略模式
// ✅ 好实践:使用策略模式处理不同支付方式
public interface PaymentStrategy {
boolean pay(BigDecimal amount);
}
public class CreditCardPayment implements PaymentStrategy {
@Override
public boolean pay(BigDecimal amount) {
// 信用卡支付逻辑
return true;
}
}
public class PayPalPayment implements PaymentStrategy {
@Override
public boolean pay(BigDecimal amount) {
// PayPal支付逻辑
return true;
}
}
public class ShoppingCart {
private final List<Item> items = new ArrayList<>();
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout() {
BigDecimal total = calculateTotal();
if (paymentStrategy.pay(total)) {
// 结账成功
}
}
}
测试最佳实践
单元测试示例
// ✅ 好实践:编写全面测试
public class CalculatorTest {
@Test
void testDivideWithPositiveNumbers() {
Calculator calculator = new Calculator();
assertEquals(5.0, calculator.divide(10, 2), 0.001);
}
@Test
void testDivideByZero() {
Calculator calculator = new Calculator();
assertThrows(IllegalArgumentException.class,
() -> calculator.divide(10, 0),
"Division by zero should throw exception");
}
@Test
void testDivideWithNegativeNumbers() {
Calculator calculator = new Calculator();
assertEquals(-5.0, calculator.divide(-10, 2), 0.001);
}
@Test
void testDivideWithLargeNumbers() {
Calculator calculator = new Calculator();
assertEquals(1.0, calculator.divide(1000000, 1000000), 0.001);
}
}
// 使用Mockito进行依赖隔离
@ExtendWith(MockitoExtension.class)
public class OrderServiceTest {
@Mock
private PaymentService paymentService;
@Mock
private NotificationService notificationService;
@InjectMocks
private OrderService orderService;
@Test
void testPlaceOrderSuccessfully() {
// 准备测试数据
Order order = new Order("123", BigDecimal.valueOf(99.99));
// 配置Mock行为
when(paymentService.processPayment(any(Payment.class)))
.thenReturn(true);
// 执行测试
OrderResult result = orderService.placeOrder(order);
// 验证结果
assertTrue(result.isSuccess());
verify(notificationService).sendOrderConfirmation(order);
}
}
代码风格与文档
使用Optional避免NullPointerException
// ❌ 坏实践:返回null
public User findUserById(Long id) {
// ...
return null; // 调用方需要检查null
}
// ✅ 好实践:返回Optional
public Optional<User> findUserById(Long id) {
// ...
return Optional.ofNullable(user);
}
// 使用示例
findUserById(123L)
.ifPresentOrElse(
user -> System.out.println("Found: " + user.getName()),
() -> System.out.println("User not found")
);
JavaDoc文档注释
/**
* 订单处理服务,负责订单的创建、更新和取消操作。
*
* <p>该类是线程安全的,所有公共方法都支持并发调用。</p>
*
* @author Zhang San
* @version 1.0
* @since 2023-01-01
*/
public class OrderService {
/**
* 根据订单ID获取订单信息。
*
* @param orderId 订单唯一标识符,不能为null
* @return 包含订单信息的Optional对象
* @throws IllegalArgumentException 如果orderId为null
* @throws OrderNotFoundException 如果订单不存在
*/
public Optional<Order> getOrderById(@NonNull Long orderId) {
// 实现代码
}
}
日志最佳实践
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PaymentProcessor {
private static final Logger log = LoggerFactory.getLogger(PaymentProcessor.class);
public void processPayment(Payment payment) {
log.debug("Processing payment: {}", payment.getId());
try {
// 处理支付逻辑
log.info("Payment {} processed successfully", payment.getId());
} catch (PaymentException e) {
log.error("Failed to process payment {}", payment.getId(), e);
throw e; // 重新抛出异常,由上层处理
}
}
}
这些最佳实践案例涵盖了Java开发中常见的场景,遵循这些实践可以提高代码质量、可维护性和性能,最佳实践不是一成不变的规则,而是应该根据具体项目需求和团队约定进行调整。
