最近在公司做項目時,有一個小功能點就是身份證號碼校驗,即判斷是否是合理的身份證號碼。不想重複造輪子,想着公司的一些基礎組件可能有這個功能,一找還真有,原作者代碼邏輯應該是正確的,但是風格有點呵呵了,各種嵌套if … else…,也不是說這樣就不好,但是有更好的流程控制寫法。那就是衛語句,這種寫法我也是看了阿里巴巴java開發手冊才知道,也推薦大家去看看。
那麼什麼是衛語句呢?先想一個業務場景,很多時候真正的業務代碼可能在嵌套多次才執行,其他分支只是簡單報錯返回的情況。如果嵌套過多,當你讀到最裏面一層的時候,估計你已經記不起來前面的條件判斷邏輯了,爲了簡化這種情況,可以把特殊情況隔離到立即結束執行的單獨條件中,也可以叫做“失敗前置”,只要有一個條件不通過,就快速返回失敗,如果到了最後一行,說明前面所有判斷都通過,剩下的就是執行你真正的業務代碼。在重構法則上,這種就叫Guard Clause法則,就是衛語句。這種程序結構優點就是可以把我們的視線從多層嵌套的層層判斷處理中解放出來,集中精力處理真正的業務代碼,且能夠使得代碼結構清晰可讀,方便後續維護。
下面是身份證號碼校驗代碼原版本及我改寫的衛語句版本,大家可以對比看下。
// 身份證號碼校驗——原始版本
public static boolean checkIdentifyNumber(String identifyNumber) {
if (StringUtils.isBlank(identifyNumber)) {
return false;
} else {
identifyNumber = identifyNumber.toLowerCase();
String[] ValCodeArr = new String[]{"1", "0", "x", "9", "8", "7", "6", "5", "4", "3", "2"};
String[] Wi = new String[]{"7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2"};
String Ai = "";
if (identifyNumber != null && (identifyNumber.length() == 18 || identifyNumber.length() == 15)) {
if (identifyNumber.length() == 18) {
Ai = identifyNumber.substring(0, 17);
} else if (identifyNumber.length() == 15) {
Ai = identifyNumber.substring(0, 6) + "19" + identifyNumber.substring(6, 15);
}
if (!isNumeric(Ai)) {
// 身份證18位號碼除最後一位外,都應爲數字
return false;
} else {
String strYear = Ai.substring(6, 10);
String strMonth = Ai.substring(10, 12);
String strDay = Ai.substring(12, 14);
if (!isDataFormat(strYear + "-" + strMonth + "-" + strDay)) {
// 身份證生日無效
return false;
} else {
GregorianCalendar gc = new GregorianCalendar();
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
try {
if (gc.get(1) - Integer.parseInt(strYear) > 150 || gc.getTime().getTime() - s.parse(strYear + "-" + strMonth + "-" + strDay).getTime() < 0L) {
// 身份證生日不在有效範圍
return false;
}
} catch (Exception var14) {
var14.printStackTrace();
return false;
}
if (Integer.parseInt(strMonth) <= 12 && Integer.parseInt(strMonth) != 0) {
if (Integer.parseInt(strDay) <= 31 && Integer.parseInt(strDay) != 0) {
Map<String, String> h = getAreaCode();
if (h.get(Ai.substring(0, 2)) == null) {
// 身份證地區編碼錯誤
return false;
} else {
int TotalmulAiWi = 0;
int modValue;
for(modValue = 0; modValue < 17; ++modValue) {
TotalmulAiWi += Integer.parseInt(String.valueOf(Ai.charAt(modValue))) * Integer.parseInt(Wi[modValue]);
}
modValue = TotalmulAiWi % 11;
String strVerifyCode = ValCodeArr[modValue];
Ai = Ai + strVerifyCode;
if (identifyNumber.length() == 18 && !Ai.equalsIgnoreCase(identifyNumber)) {
// 身份證無效,不是合法的身份證號碼
return false;
} else {
return true;
}
}
} else {
// 身份證日期無效
return false;
}
} else {
// 身份證月份無效
return false;
}
}
}
} else {
// 身份證長度錯誤
return false;
}
}
}
// 身份證號碼校驗——衛語句版本
public static boolean checkIdentifyNumber(String identifyNumber) {
if (StringUtils.isBlank(identifyNumber)) {
return false;
}
identifyNumber = identifyNumber.toLowerCase();
String[] ValCodeArr = new String[]{"1", "0", "x", "9", "8", "7", "6", "5", "4", "3", "2"};
String[] Wi = new String[]{"7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2"};
String Ai = "";
if (identifyNumber.length() != 18 && identifyNumber.length() != 15) {
// 身份證長度錯誤
return false;
}
if (identifyNumber.length() == 18) {
Ai = identifyNumber.substring(0, 17);
}
if (identifyNumber.length() == 15) {
Ai = identifyNumber.substring(0, 6) + "19" + identifyNumber.substring(6, 15);
}
if (!isNumeric(Ai)) {
// 身份證18位號碼除最後一位外,都應爲數字
return false;
}
String strYear = Ai.substring(6, 10);
String strMonth = Ai.substring(10, 12);
String strDay = Ai.substring(12, 14);
if (!isDataFormat(strYear + "-" + strMonth + "-" + strDay)) {
// 身份證生日無效
return false;
}
GregorianCalendar gc = new GregorianCalendar();
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
try {
if (gc.get(Calendar.YEAR) - Integer.parseInt(strYear) > 150 || gc.getTime().getTime() - s.parse(strYear + "-" + strMonth + "-" + strDay).getTime() < 0L) {
// 身份證生日不在有效範圍
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
if (Integer.parseInt(strMonth) > 12 || Integer.parseInt(strMonth) <= 0) {
// 身份證月份無效
return false;
}
if (Integer.parseInt(strDay) > 31 && Integer.parseInt(strDay) <= 0) {
// 身份證日期無效
return false;
}
Map<String, String> h = getAreaCode();
if (h.get(Ai.substring(0, 2)) == null) {
// 身份證地區編碼錯誤
return false;
}
int TotalmulAiWi = 0;
int modValue;
for(modValue = 0; modValue < 17; ++modValue) {
TotalmulAiWi += Integer.parseInt(String.valueOf(Ai.charAt(modValue))) * Integer.parseInt(Wi[modValue]);
}
modValue = TotalmulAiWi % 11;
String strVerifyCode = ValCodeArr[modValue];
Ai = Ai + strVerifyCode;
if (identifyNumber.length() == 18 && !Ai.equalsIgnoreCase(identifyNumber)) {
// 身份證無效,不是合法的身份證號碼
return false;
}
return true;
}