從普通到優(yōu)秀!Java 資深開發(fā)者是如何審查代碼的?
在這篇文章中,我們將一起進行幾次代碼審查,同時學(xué)習(xí)在審查時需要關(guān)注哪些問題。還會討論如何以專業(yè)且尊重的態(tài)度參與代碼審查。
話不多說,讓我們開始吧!
審查1:發(fā)現(xiàn)常見錯誤
在審查任何代碼時,我首先關(guān)注有沒有一些常見但容易被忽視的錯誤。
來看下面這段代碼,找找其中的問題:
package com.icoderoad.order;
import java.util.List;
public class OrderProcessor {
private final List<Order> orders;
public OrderProcessor(List<Order> orders) {
this.orders = orders;
}
public void processOrders() {
for (Order order : orders) {
if ("Paid".equals(order.getOrderStatus())) {
order.setOrderStatus("Shipped");
System.out.println("Order " + order.getOrderId() + " is now Shipped.");
} else if ("Shipped".equals(order.getOrderStatus())) {
order.setOrderStatus("Completed");
System.out.println("Order " + order.getOrderId() + " is now Completed.");
}
}
}
}
class Order {
private int orderId;
private String orderStatus;
private double totalAmount;
// getters and setters
}
你發(fā)現(xiàn)什么問題了嗎?沒錯!這段代碼存在:
- 缺少異常處理(沒有 try-catch)
- 硬編碼字符串("Paid"、"Shipped")
- 命名風(fēng)格不統(tǒng)一(
orderId
vsorderStatus
vstotalAmount
)
修正后的版本:
package com.icoderoad.order;
import java.util.List;
public class OrderProcessor {
private final List<Order> orders;
public OrderProcessor(List<Order> orders) {
this.orders = orders;
}
public void processOrders() {
for (Order order : orders) {
try {
switch (order.getStatus()) {
case PAID -> {
order.setStatus(OrderStatus.SHIPPED);
System.out.println("Order " + order.getId() + " is now Shipped.");
}
case SHIPPED -> {
order.setStatus(OrderStatus.COMPLETED);
System.out.println("Order " + order.getId() + " is now Completed.");
}
default -> System.out.println("Order " + order.getId() + " has an unknown status: " + order.getStatus());
}
} catch (Exception ex) {
System.err.println("Error processing order " + order.getId() + ": " + ex.getMessage());
}
}
}
}
package com.icoderoad.order;
public class Order {
private int id;
private OrderStatus status;
private double totalAmount;
// getters and setters
}
package com.icoderoad.order;
public enum OrderStatus {
PAID,
SHIPPED,
COMPLETED
}
審查2:遺漏空值檢查(Null Check)
再來看這段:
package com.icoderoad.customer;
import java.util.List;
public class OrderProcessor {
public void getCustomerOrderDetails(Customer customer) {
if (customer.getOrders().size() > 0) {
for (Order order : customer.getOrders()) {
System.out.println("Order ID: " + order.getId() + ", Amount: " + order.getAmount());
}
} else {
System.out.println("No orders found.");
}
}
}
發(fā)現(xiàn)問題了嗎?正確!這里缺少空值檢查,如果 customer
或 orders
為 null
,就直接崩潰了!
修正后的版本:
package com.icoderoad.customer;
import java.util.List;
public class OrderProcessor {
public void getCustomerOrderDetails(Customer customer) {
if (customer == null) {
System.out.println("Customer is null.");
return;
}
List<Order> orders = customer.getOrders();
if (orders == null || orders.isEmpty()) {
System.out.println("No orders found.");
return;
}
for (Order order : orders) {
System.out.println("Order ID: " + order.getId() + ", Amount: " + order.getAmount());
}
}
}
審查3:強耦合(Tight Coupling)
繼續(xù)看:
package com.icoderoad.order;
public class OrderService {
private final PaymentService paymentService = new PaymentService();
public void processOrder(Order order) {
paymentService.processPayment(order);
}
}
沒錯,這是強耦合設(shè)計!OrderService
直接綁定了具體實現(xiàn),難以測試和擴展。
更好的方式:使用接口 + 構(gòu)造器注入(Dependency Injection)
package com.icoderoad.order;
public class OrderService {
private final IPaymentService paymentService;
public OrderService(IPaymentService paymentService) {
this.paymentService = paymentService;
}
public void processOrder(Order order) {
paymentService.processPayment(order);
}
}
審查4:神秘數(shù)字(Magic Numbers)
你的朋友寫了稅率邏輯:
package com.icoderoad.tax;
public class TaxCalculator {
public double calculateTax(double income) {
if (income <= 50000) return income * 0.10;
if (income <= 100000) return income * 0.15;
if (income <= 200000) return income * 0.20;
return income * 0.30;
}
}
這里有大量魔法數(shù)字,后期改動會非常痛苦。
更好的設(shè)計:
package com.icoderoad.tax;
import java.util.List;
public class TaxCalculator {
private final List<Double> incomeSlabs;
private final List<Double> taxRates;
public TaxCalculator(List<Double> incomeSlabs, List<Double> taxRates) {
this.incomeSlabs = incomeSlabs;
this.taxRates = taxRates;
}
public double calculateTax(double income) {
for (int i = 0; i < incomeSlabs.size(); i++) {
if (income <= incomeSlabs.get(i)) {
return income * taxRates.get(i);
}
}
return income * taxRates.get(taxRates.size() - 1);
}
}
配合配置文件或常量管理,維護性更高!
審查5:別重復(fù)你自己(DRY)
看下面的代碼:
package com.icoderoad.discount;
public class DiscountCalculator {
public double calculateDiscount(double amount, double discountPercentage) {
double discount = amount * discountPercentage;
return amount - discount;
}
public double applyDiscount(double amount, double discountPercentage) {
double discount = amount * discountPercentage;
return amount - discount;
}
}
這里明顯重復(fù)了邏輯!
正確版本:
package com.icoderoad.discount;
public class DiscountCalculator {
public double calculateDiscount(double amount, double discountPercentage) {
return applyDiscount(amount, discountPercentage);
}
public double applyDiscount(double amount, double discountPercentage) {
return amount - calculateDiscountAmount(amount, discountPercentage);
}
private double calculateDiscountAmount(double amount, double discountPercentage) {
return amount * discountPercentage;
}
}
審查6:YAGNI原則(You Aren’t Gonna Need It)
最后,來看這段帶優(yōu)惠券處理的代碼:
package com.icoderoad.order;
public class OrderProcessor {
public void processOrder(Order order, double discount) {
double discountAmount = order.getAmount() * discount;
double finalAmount = order.getAmount() - discountAmount;
System.out.println("Discount Applied: " + discountAmount);
if (order.getCouponCode() != null) {
double couponDiscount = applyCoupon(order.getCouponDiscount());
finalAmount -= couponDiscount;
System.out.println("Coupon " + order.getCouponCode() + " applied.");
}
}
private double applyCoupon(double couponDiscount) {
return couponDiscount;
}
}
問題在于:需求只要做折扣,卻提前加了優(yōu)惠券邏輯,增加了不必要復(fù)雜性!
遵循 YAGNI 原則:只做需求中需要的內(nèi)容。
精簡版:
package com.icoderoad.order;
public class OrderProcessor {
public void processOrder(Order order, double discount) {
double discountAmount = order.getAmount() * discount;
double finalAmount = order.getAmount() - discountAmount;
System.out.println("Discount Applied: " + discountAmount);
}
}
總結(jié)
一個優(yōu)秀的 Java 開發(fā)者,在代碼審查時應(yīng)該特別關(guān)注:
- 是否有異常處理和日志
- 命名風(fēng)格是否統(tǒng)一
- 是否避免了魔法數(shù)字
- 是否做了空值檢查
- 是否違反 DRY 原則
- 是否提前開發(fā)了無關(guān)功能(YAGNI)
- 是否有合理的接口隔離和依賴注入設(shè)計
審代碼,不止是挑刺,更是讓團隊代碼整體更健康、更易維護!