Java 1.5 引入 System.getenv(),提供跨平台存取作業系統環境變數的標準 API。本文詳細說明單一變數讀取、全量遍歷、區域化編碼注意事項與容器化部署最佳實務。
// 讀取單一環境變數(不存在回傳 null)
String os = System.getenv("OS"); // Windows_NT / Linux / Darwin
String javaHome = System.getenv("JAVA_HOME");
String path = System.getenv("PATH");
// 取得所有環境變數(不可修改的 Map)
Map<String, String> env = System.getenv();
// 注意:Map 為 unmodifiable,嘗試 put/remove 會拋 UnsupportedOperationException
import java.util.Map;
public class EnvDump {
public static void main(String[] args) {
Map<String, String> env = System.getenv();
// 按鍵名排序輸出,方便閱讀
env.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(entry -> System.out.println(entry.getKey() + "=" + entry.getValue()));
}
}
// Windows 環境
ALLUSERSPROFILE=C:\ProgramData
APPDATA=C:\Users\user\AppData\Roaming
CLASSPATH=.;C:\java\lib
COMMONPROGRAMFILES=C:\Program Files\Common Files
COMPUTERNAME=DESKTOP-ABC123
JAVA_HOME=C:\Program Files\Java\jdk-17
NUMBER_OF_PROCESSORS=8
OS=Windows_NT
PATH=C:\Windows\system32;C:\Windows;C:\Program Files\Java\jdk-17\bin
PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 158 Stepping 10, GenuineIntel
TEMP=C:\Users\user\AppData\Local\Temp
USERNAME=user
USERPROFILE=C:\Users\user
WINDIR=C:\Windows
// Linux/Docker 環境
HOME=/root
HOSTNAME=container-abc123
JAVA_HOME=/usr/lib/jvm/java-17-openjdk
LANG=en_US.UTF-8
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/app
TERM=xterm
public class Config {
// 必要變數:不存在拋出異常
public static final String DB_URL = requiredEnv("DB_URL");
public static final String DB_USER = requiredEnv("DB_USER");
public static final String DB_PASS = requiredEnv("DB_PASS");
// 可選變數:提供預設值
public static final int PORT = Integer.parseInt(optionalEnv("PORT", "8080"));
public static final String ENV = optionalEnv("ENV", "development");
private static String requiredEnv(String key) {
String value = System.getenv(key);
if (value == null || value.isBlank()) {
throw new IllegalStateException("環境變數 " + key + " 未設定");
}
return value;
}
private static String optionalEnv(String key, String defaultValue) {
String value = System.getenv(key);
return (value != null && !value.isBlank()) ? value : defaultValue;
}
}
String env = System.getenv("ENVIRONMENT"); // development, staging, production
boolean isProd = "production".equalsIgnoreCase(env);
boolean isDocker = System.getenv("DOCKER_CONTAINER") != null;
boolean isK8s = System.getenv("KUBERNETES_SERVICE_HOST") != null;
// Kubernetes Downward API 注入
String cpuLimit = System.getenv("CPU_LIMIT"); // 如 "2000m" = 2 cores
String memLimit = System.getenv("MEMORY_LIMIT"); // 如 "512Mi"
// 轉換為 JVM 參數邏輯...
| 平台 | 鍵名大小寫 | 編碼 | 備註 |
|---|---|---|---|
| Windows | 不區分大小寫 | 系統預設 (CP950/CP1252/UTF-8) | System.getenv("path") == System.getenv("PATH") |
| Linux/Unix | 區分大小寫 | 通常 UTF-8 | PATH != Path != path |
| macOS | 區分大小寫 | UTF-8 |
最佳實務:統一使用大寫鍵名(如 JAVA_HOME),在容器中透過 env 指令驗證實際注入值。
Java 無標準 API 修改 OS 環境變數,但可透過反射修改 System.getenv() 回傳的 Map(僅影響當前 JVM 後續讀取):
@SuppressWarnings("unchecked")
public static void setEnv(String key, String value) {
try {
Map<String, String> env = System.getenv();
Class<?> cl = env.getClass();
if (cl.getName().equals("java.util.Collections$UnmodifiableMap")) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Map<String, String> delegate = (Map<String, String>) field.get(env);
delegate.put(key, value);
}
} catch (Exception e) {
throw new IllegalStateException("無法設定環境變數", e);
}
}
// 僅供測試用途,生產環境勿用
.env 檔案(使用 dotenv-java 載入),生產環境強制要求環境變數存在。System.getenv() 是 Java 應用與作業系統/容器環境溝通的橋樑。掌握單一讀取、全量遍歷、跨平台大小寫差異、容器化注入模式,並建立專案統一的 EnvUtils 工具類,能顯著提升應用的可移植性與安全性。