1.0.0-alpha, 2.5.6-rc.1, 8.5c。1.0 vs 1.0.0.0。"9.9" > "10.8" (按字典序)。.) 分割成段數組。1.0.0 > 1.0)。
public final class VersionUtil {
private VersionUtil() {}
/**
* 比較兩個版本號
* @return v1 > v2 返回 1; v1 < v2 返回 -1; 相等返回 0
*/
public static int compare(String v1, String v2) {
if (v1 == null || v2 == null) throw new IllegalArgumentException("版本號不能為空");
String[] s1 = v1.split("\\."); // 轉義 .
String[] s2 = v2.split("\\.");
int len = Math.min(s1.length, s2.length);
for (int i = 0; i < len; i++) {
String seg1 = s1[i];
String seg2 = s2[i];
// 先比長度 (數值位數)
int cmp = Integer.compare(seg1.length(), seg2.length());
if (cmp != 0) return cmp > 0 ? 1 : -1;
// 長度相等,按字符串自然序 (支援字母、數字混合)
cmp = seg1.compareTo(seg2);
if (cmp != 0) return cmp > 0 ? 1 : -1;
}
// 前綴段完全相等,段數多者大
return Integer.compare(s1.length, s2.length);
}
// 便捷方法
public static boolean isGreater(String v1, String v2) { return compare(v1, v2) > 0; }
public static boolean isLess(String v1, String v2) { return compare(v1, v2) < 0; }
public static boolean isEqual(String v1, String v2) { return compare(v1, v2) == 0; }
}
@Test
public void testCompare() {
assertEquals(1, VersionUtil.compare("10.8.8.6", "9.9")); // 主版本位數不同
assertEquals(1, VersionUtil.compare("9.9b", "9.8a")); // 字母後綴
assertEquals(1, VersionUtil.compare("1.0.0", "1.0")); // 更多段數
assertEquals(0, VersionUtil.compare("1.0.0", "1.0.0"));
assertEquals(-1, VersionUtil.compare("1.0.0-alpha", "1.0.0")); // 字母 < 空/數字 (視具體規則)
}
若需嚴格遵循 SemVer 2.0 (Major.Minor.Patch[-PreRelease][+BuildMeta]),建議引入成熟庫:
// Maven
com.github.zafarkhaja
java-semver
0.9.0
// 使用
Version v1 = Version.valueOf("1.0.0-alpha.1");
Version v2 = Version.valueOf("1.0.0");
v1.compareTo(v2); // -1
split("\\."),否則 . 匹配任意字符。"1.05" vs "1.5",長度比較法視為 1.05 > 1.5;若需數值相等,先 Integer.parseInt 再比較 (但會丟失字母支持)。-、_,按實際規範調整 split 參數。compareTo 區分大小寫,統一規範為小寫或按 ASCII 序。版本號比較核心在於**「分段 → 比長度 → 比字典序 → 比段數」**。自行實現 20 行代碼即可覆蓋 90% 場景;嚴格 SemVer 合規項目請引入專用庫,避免邊界情況踩坑。