核心觀念:Java 沒有「全域變數」
Java 是純物件導向語言,所有資料必須歸屬於類別。所謂「全域常數」實際上是 類別層級的 static final 欄位,透過類別名存取:Math.PI、Config.MAX_RETRY。
方案一:介面常量模式(不推薦用於新專案)
public interface AppConstants {
int DEFAULT_PORT = 8080;
String DEFAULT_HOST = "localhost";
boolean DEBUG_MODE = true;
}
// 使用:實作介面即可直接存取常量名
public class MyService implements AppConstants {
public void connect() {
System.out.println("Port: " + DEFAULT_PORT); // 直接用常量名
}
}
- 缺點:實作介面洩露實作細節、破壞介面契約語意、常量污染命名空間、無法演進為可配置
- 現狀:Java 5+ 引入靜態導入後已無優勢,**強烈不建議**在新代碼使用
方案二:常量類(最終類 + 私有建構子)
public final class Constants {
// 防止實例化
private Constants() {
throw new AssertionError("常量類不可實例化");
}
public static final int DEFAULT_PORT = 8080;
public static final String DEFAULT_HOST = "localhost";
public static final boolean DEBUG_MODE = true;
// 編譯期常量(基本型別 + String)會內聯到呼叫端
// 運行期常量(new 物件、方法呼叫)不會內聯
}
// 使用
public class MyService {
public void connect() {
System.out.println("Port: " + Constants.DEFAULT_PORT);
}
}
- 優點:語意清晰、防實例化、支援靜態導入
import static Constants.*
- 適用:真正的編譯期常數、極少變動的基礎常數
方案三:配置屬性類(支援外部化配置)
@ConfigurationProperties(prefix = "app")
@Data
public class AppProperties {
private int port = 8080;
private String host = "localhost";
private boolean debug = false;
// 巢狀配置
private Database db = new Database();
@Data
public static class Database {
private String url;
private String username;
private String password;
}
}
// Spring Boot 啟用
@EnableConfigurationProperties(AppProperties.class)
@SpringBootApplication
public class Application { }
- 優點:支援 YAML/Properties/環境變數/命令列參數多源覆蓋、熱更新、類型安全綁定、驗證(JSR-303)
- 適用:所有可能隨環境變化的配置項
方案四:分散式配置中心(微服務標配)
| 方案 | 特點 | 適用階段 |
| Nacos | 阿里開源、支援動態刷新、灰度發布、權限控制 | 微服務生產環境 |
| Apollo | 攜程開源、灰度發布、版本管理、審核流程 | 大型企業微服務 |
| Spring Cloud Config | Git 後端、Spring 生態整合 | 中小型微服務 |
| Consul / Etcd | 服務發現 + KV 存儲、強一致性 | 基礎設施已有的團隊 |
常量分類與選型指南
| 類型 | 範例 | 推薦方案 | 理由 |
| 數學/物理常數 | PI、E、光速 | 方案二(常量類) | 永不變動,編譯期內聯最優 |
| 業務固定規則 | 訂單狀態枚舉、最大重試次數 | 方案二 或 枚舉類 | 隨代碼發布變更,版本控管 |
| 環境相關配置 | 資料庫連線、第三方 API 金鑰、功能開關 | 方案三(@ConfigurationProperties) | 各環境不同,需外部化、加密、審計 |
| 動態業務參數 | 限流閾值、促銷折扣、AB 測試權重 | 方案四(配置中心) | 運行期調整、無需重啟、灰度發布 |
避坑指南
- 別用
public static 非 final 欄位當全域變數:執行緒不安全、難以測試、隱性耦合
- 常量類勿過度膨脹:按業務域拆分
OrderConstants、PaymentConstants
- 敏感資訊絕不寫在代碼:密碼、金鑰必須走配置中心 + 加密
- 利用枚舉替代 int/String 常量組:類型安全、IDE 智能提示、防非法值
現代最佳實踐總結
// 1. 基礎常數 → final class + static final
public final class MathConstants {
private MathConstants() {}
public static final double PI = 3.141592653589793;
}
// 2. 業務枚舉 → enum
public enum OrderStatus {
PENDING, PAID, SHIPPED, COMPLETED, CANCELLED
}
// 3. 環境配置 → @ConfigurationProperties
@ConfigurationProperties("app.storage")
@Data
public class StorageProperties {
private String bucket;
private String region;
private int maxFileSizeMb = 100;
}
// 4. 動態參數 → 配置中心客戶端註解
@NacosConfigurationProperties(dataId = "dynamic-rules", autoRefreshed = true)
@Data
public class DynamicRules {
private int rateLimitQps = 1000;
private double discountRate = 0.9;
}
總結
Java 常量定義已從「介面常量」演進為「分層配置管理」。核心原則:**業務不變的用常量類/枚舉,環境相關的用外部化配置,運行期調整的用配置中心**。這樣既保證了類型安全與編譯期優化,又滿足了雲原生時代的動態配置需求。
- 上一篇文章: Java 漢字轉拼音實戰:基於 pinyin4j 庫完整實現
- 下一篇文章: Java 正則表達式驗證郵箱與手機號:完整規則解析與生產級工具類
Copyright ©
程式碼之家 All Rights Reserved