前言
只有光頭才能變強。
文本已收錄至我的GitHub倉庫,歡迎Star:https://github.com/ZhongFuCheng3y/3y
記錄一次在寫代碼時愚蠢的操作,本文涉及到的知識點:String不可變性
一、交代背景
我這邊有一個系統,提供一個RPC接口去發送短信。外部調用我的接口需要傳入手機號等等參數,我這邊負責解析這些參數、做一些業務的處理,然后調用短信渠道商的接口發送短信。
每當調用完短信渠道商的接口時,我會對這次發送的記錄入庫(存入MySQL中),同樣地短信渠道商會返回發送或失敗的回執給我,我也會入庫(存入MySQL中)。
那天,有人來找到我,說某個手機號收不到短信,用戶並沒有屏蔽短信(欠費、關機)等等一些操作,就是收不到短信。
於是我就去排查啦,首先我先去DB里邊找有沒有對應的發送記錄,發現這條記錄是存在的,而且在DB上看不出來有什么異常。
- 所以,這就排除了這個操作在中途被攔截的情況(因為已經入庫了,就肯定調用過短信運營商的接口)
后來就去撈日志,看看調用短信運營商返回的Result對象的信息是什么,然后就去問了一下短信運營商可能出現這種問題的原因是什么。那邊回復的是:“如果是部分的手機號出現這種狀況,是不是你們的手機號沒有trim啊?”
於是,我又去撈日志,發現手機號后面真的帶有一個空格(扎心了,之前一直看不到)。要處理這個問題就變得異常簡單了,我只要在入口里邊對手機號進行trim就好了。
二、編寫代碼
我這邊是支持同一條短信向多個手機號發送,於是手機號我這邊用的是HashSet來進行接收。對手機號進行trim我寫下了如下的代碼:
// 說明:Task對象 有個 key屬性,這個key屬性的類型是HashSet
if (task.getKey() != null && task.getKey().size() > 0) {
for (String s : task.getKey()) {
s.trim();
}
}
代碼很簡單,我做的就兩步:
- 判斷是否為null,不為null值則遍歷手機號集合
- 對每個手機號進行trim
上面的代碼有問題嗎?必須有問題啊,沒問題我還寫啥。
下面寫個小Demo,我們會發現:在代碼的11行上調用trim()
方法后,在12行再輸出,還是會有空格的情況。
2.1 為什么會有這種錯覺?
其實,我們在初學Java的時候,肯定會學到String類。在學習的時候也是明確String是不可變的,但總是有個感覺我們把String對象給改了,為什么?
我覺得第一點是這樣的:我們操作的往往是可變的對象,對象的某些屬性改了,我們就認為已經改了。比如下面的代碼:
HashSet<Student> students = getStudent();
for (Student s1 : students) {
s1.setName("Java3y");
}
執行完,我們就認為在HashSet里邊的Student的名字全改成Java3y了,而實際上也是如此。
我覺得第二點是這樣的:我們平時操作String對象,都是直接把操作后的結果傳過去,這看起來就像修改原對象了一樣。比如下面類似的代碼:
// 去重
String phone = " 137888888888 ";
sendPhone(phone.trim());
// 轉成大寫后輸出
System.out.println(phone.toUpperCase());
// ... 等等
2.2 怎么改
現在問題已經知道了,String對象是不可變的,對String對象進行操作,“看似”把原來的String對象改了,實際上是生成了一個新的String對象。
回到我那個問題,也很好解決,把trim
好的手機號設置到HashSet就行了
// 說明:Task對象 有個 key屬性,這個key屬性的類型是HashSet
HashSet<String> hs = new HashSet();
if (task.getKey() != null && task.getKey().size() > 0) {
for (String s : task.getKey()) {
hs.add(s.trim());
}
}
task.setKey(hs);
最后
這個B寫了一篇文章來解釋自己是怎么“合理“寫Bug的,真不要臉。
樂於輸出干貨的Java技術公眾號:Java3y。公眾號內有200多篇原創技術文章、海量視頻資源、精美腦圖,關注即可獲取!
覺得我的文章寫得不錯,點贊!