解析一下阿里出品的泰山版 Java 開發手冊
說起華山,我就想起嶽不群,不,令狐沖;說起泰山,我就想起司馬遷,他的那句名言“人總有一死,或重於泰山,或輕於鴻毛”,真的發人深省啊。這就意味著,阿里出品的泰山版 Java 開發手冊,是迄今為止最重量級的。
華山版是上個版本,啥時候更新的呢?2019 年 06 月 13 號,距離現在 10 個月了,時間也不短了,是時候更新了。
新版都更新了哪些內容呢?可以從官方的版本歷史中看得出來。
01、釋出錯誤碼統一解決方案
錯誤碼用來幹嘛呢?答案是異常日誌,方便我們快速知曉錯誤來源,判斷是誰那出的問題。上圖中 A 表示錯誤來源於使用者;還有 B 級的,表示錯誤來源於當前系統;C 級的,表示錯誤來源於第三方服務,比如 CDN 伺服器。
這個解決方案還是值得借鑑的,很多成熟的系統都在使用錯誤碼,如果你對接過微信支付的話,應該對錯誤碼不會感到陌生。看到錯誤碼,然後在手冊中搜索一下,就能快速知曉錯誤的型別,還是很不錯的。
02、新增 34 條新的規約
34 條太多了,我就挑幾個重要的拉出來說一說吧。
1)日期時間
還記得上次技術圈的刷屏事件吧?就是那個 YYYY 和 yyyy 造成的問題。大寫的 Y 表示的是當天所在的這一週是屬於哪個年份的,小寫的 y 表示的是當天所在的年份,差別還是挺大的。你品,你細品。
還有,大寫的 M 和 小寫的 m 是不同的,大寫的 H 和小寫的 h 也是不同的。
另外,像獲取當前毫秒數應該使用 System.currentTimeMillis()
new Date().getTime()
,這些細緻的規約,都應該牢記在心中,不要去犯這些低階的錯誤。
2)三目運算的 NPE 問題
說實話,這個問題我之前從來沒有注意,這次看到了,就一起來學習一下。先來看下面這段程式碼:
public class TestCondition {
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = null;
Boolean flag = false;
Integer result = flag ? a * b : c;
}
}
條件 a * b
屬於算術運算,它倆相乘後的結果是一個 int 型別,這就會導致 c 這個 Integer 型別自動拆箱,由於值為 null,就丟擲了以下錯誤:
Exception in thread "main" java.lang.NullPointerException
at com.cmower.mkyong.TestCondition.main(TestCondition.java:9)
那可能你會感到好奇,為什麼兩個 Integer 型別的變數相乘後會是一個 int 型別呢,這主要是由編譯器決定的,它就是這麼設計的,來看一下反編譯後的位元組碼:
public class TestCondition
{
public static void main(String args[])
{
Integer a = Integer.valueOf(1);
Integer b = Integer.valueOf(2);
Integer c = null;
Boolean flag = Boolean.valueOf(false);
Integer result = Integer.valueOf(flag.booleanValue() ? a.intValue() * b.intValue() : c.intValue());
}
}
a * b
時發生了自動拆箱,呼叫了 intValue()
方法,而三元運算的兩個表示式的型別必須一致,這就導致 c 也呼叫了 intValue()
方法,由於 c 本身為 null,那就只能 NPE 了。明白了吧?
3)Collectors 類的 toMap()
方法
手冊上說,在使用 java.util.stream.Collectors
類的 toMap()
方法轉 Map 時,一定要使用含有引數型別為 BinaryOperator,引數名為 mergeFunction 的方法,否則當出現相同 key 值時會丟擲 IllegalStateException 異常。
這段話可能理解上有點難度,那先來看一段程式碼吧!
String[] departments = new String[] {"沉默王二", "沉默王二", "沉默王三"};
Map<Integer, String> map = Arrays.stream(departments)
.collect(Collectors.toMap(String::hashCode, str -> str));
執行這段程式碼的時候,就會丟擲異常,堆疊資訊如下所示:
Exception in thread "main" java.lang.IllegalStateException: Duplicate key 867758096 (attempted merging values 沉默王二 and 沉默王二)
at java.base/java.util.stream.Collectors.duplicateKeyException(Collectors.java:133)
at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:180)
key 重複了,因為兩個“沉默王二”的 hashCode 相同,那這時候的解決辦法呢?
String[] departments = new String[] {"沉默王二", "沉默王二", "沉默王三"};
Map<Integer, String> map = Arrays.stream(departments)
.collect(Collectors.toMap(String::hashCode, str -> str, (v1, v2) -> v2));
多加個引數 (v1, v2) -> v2
,也就是重複的時候選一個。來看看此時呼叫的 toMap()
方法吧。
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction) {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
BinaryOperator 和 mergeFunction 是不是出現了?
03、修改描述 90 處
手冊上說,比如,阻塞等待鎖、建表的小數型別等描述有修改,我特麼花了半個小時也沒有找出來和上一個版本之間的差別。
不知道是不是手冊的小編在瞎說,你要是能發現差別,告訴我一聲。
04、完善若干處示例
比如說 SQL 語句欄目裡的 ISNULL 的示例,確實比華山版追加了一個更詳細的反例,見下圖。
但說實話,這段反例的描述我看了至少六遍才搞懂是什麼意思。首先,不要在 null 前換行,影響閱讀性,這倒是真的;其次呢,不要使用 column is null
進行判空,使用 ISNULL(column)
判空,效率更高,也不會出現換行的情況。
select * from cms_subject where column is null and
column1 is not null;
select * from cms_subject where ISNULL(column) and
column1 is not null;
05、最後
2016 年 12 月份,阿里首次向業界開放了這份《Java 開發手冊》,到泰山版釋出,已經過去了 3 年多時間了,這份手冊也在全球 Java 開發者共同的努力下,成為業界普遍遵循的開發規範。這份手冊包含的知識點非常全面,七大維度程式設計規約、異常日誌、單元測試、安全規約、MySQL資料庫、工程規約、設計規約都有羅列。
如果你想成為一名優秀的 Java 工程師,那麼這份手冊上的內容幾乎是必須要掌握的。是不是已經迫不及待想要下載這份手冊了?如果你還沒有下載的話,請微信搜尋「沉默王二」回覆「手冊」就可以免費獲取了。最後,我衷心地祝福你,希望你能學有所成,to be better,奧利給!