最近有篇關於String空字符串判斷的文章火了,總是看到這篇文章,既然如此我也只好認真看了下:程序員曬出一段代碼引來無數網友狂噴!網友:你就活該當碼農!html
我也以爲這段代碼寫的不怎麼的,首先程序的正確性應該沒有問題,我只是以爲若是寫出的代碼跟道上承認的規範有違的話可能會噁心到後面接手的人而不自知,我如今莫名打噴嚏的時候就在想確定是在以前公司寫的代碼又被接手的人吐槽了… :)java
看上去就是個判斷字符串是否爲空字符串的方法,首先這類方法應該提取到StringUtil相似的工具類中,而這個private的權限看上去應該是在調用它的類中找了個寬敞的地就給寫上了,這種開發習慣可能會致使項目中存在一些冗餘代碼。若是對於基礎代碼的複用沒有把握好的話,當項目功能龐大到必定程度的時候用IDEA黑色主題就能看到滿滿的shi黃色以及後人從頭開始閱讀項目代碼時會不斷有這種感受:啊,這個代碼片斷我好像剛剛在哪裏看到過…我的猜想多是項目剛剛開發的時候工期比較緊,程序員心想先能跑起來再說反正之後我會重構的,固然你們都懂的,當一個程序員說之後xxx的時候八成回頭就忘…而後就這鳥樣了。程序員
扯一個話外題,若是細心的話會注意到剛纔我說的是StringUtil,關於Util類的命名也有很多的爭論,有人認爲應該是FooUtils,而有的人認爲應該是FooUtil不帶s,我我的比較承認的方法是工具類所在的包名帶s爲com.foo.utils,而其下所放的工具類則不帶s爲FooUtil,固然只是我的見解,關於這個能夠作個試驗,在一個依賴開源項目比較多的項目中使用StringUtil爲前綴一搜索就能看到不一樣開源項目也是用哪一種方式命名的都有,這個問題還真不太好下定論,反正一個項目中統一用一個風格便可。apache
而後就是我很是想吐槽的方法名這是致使我寫這篇博客的緣由,validateString是個什麼鬼,若是我前面的猜想成立,這個方法是寫在調用它的類中的話還好,由於方法名應該反映的是作了什麼而不是怎麼作,這個方法只是爲了校驗一個東西是否合法具體怎麼作不關心,可是是校驗的是什麼東西呢?String是啥?這名字更合適的是將validateString的String改成具體指代的概念,好比validateEmail/validateUserName,而若是是在StringUtil類中的話,validateString就太模糊,由於當針對字符串的操做種類比較多的時候,對其命名就應該粒度更細一些,這裏我認爲在StringUtil中這樣的操做一個更合適的方法簽名是public boolean isNotEmpty(String s),後面會針對字符串的幾種狀態及相關方法進行詳述。
接下來就是實現了,我也鬧不明白爲啥搞那麼複雜,直接return應該也能夠:編程
private boolean validateString(String str) { return str != null && !"".equals(str); }
上面用到了取反來對錶達式結果否認,取反通常腦子會須要急拐彎一下,人腦運算速度稍高不是老司機的話急拐彎容易翻車,因此編程中應該儘可能少用取反,爲了更好理解能夠再稍稍改一下:ide
private boolean validateString(String str) { return str != null && str.length() != 0; }
若是是抽取到StringUtil中的話就是:工具
public static boolean isNotEmpty(String s) { return s != null && s.length() != 0; }
另外還有一個小細節,小括號和花括號之間沒有空格,多是代碼沒有格式化過,應該格式化一下統一風格的。優化
這裏還有樓主認爲維護別人的代碼會讓本身不舒服,由於IT行業的特殊性,大部分狀況下項目的生命週期都要比開發人員在這個公司的工齡要長,一段代碼通過幾我的的手是很正常的。這裏又想扯一個話外題,就是一個以前看過的例子,具體記不清了大概就是說有我的開發了一套系統,可是留有很大的隱患估計本身也不知道,後來過了好久了問題終於爆發了,關鍵是這個時候他都升了好幾級了暫稱他爲P3,他直接下屬是P2,P2的某個倒黴的直接下屬是P1(此處級別絕無映射只是爲了方便敘述),P1找到了問題的根源發現是當初開發系統的人的考慮不周致使很難搞而後彙報給了直屬領導P2,P2要維護直屬領導P3的面子不敢讓其知道這是當年P3留下的隱患(表示不理解,這點擔當都沒有還當啥領導啊…),就想了個孬點讓P1在工做時間以外把這個問題解決了不計入正常工做,這樣也沒必要向上彙報了,而後工做時間照常給他排其它任務,倒黴的P1以爲本身很冤就在論壇發帖子把這事捅了出來讓你們評理…反正我是被唬得一愣一愣的,感受IT圈有點亂,遇到這種問題還真夠喝一壺的。google
最後還有一個想法要說,就是看到那篇文章的評論中某高級工程師的回覆,很容易讓人認爲這個行業已經變得是劣幣驅逐良幣,但願只是剛吃完飯血糖升高判斷力下降才致使發言失誤。還有就是當名字後面還掛着公司名字時候,說的話是要爲公司負責的,你這一時爽了但不當心玩脫了之後讓別人怎麼看你東家,你看我雖然級別低沒title可是寫這些沒水平的垃圾文章也仍是歷來不讓別人知道我東家是誰省得給東家丟人… :( 設計
String狀態指的是一個String類型的變量的值可能會有的幾種狀態:
null 指針爲null "" 空字符串(empty) " " 空白字符串(blank) " aabb " 字符串 "aaccbb" 只含字母 "12345" 只含數字
發現好多人都分不清空字符串(empty)和空白字符串(blank)的區別,空字符串就是長度爲0的字符串,空白字符串雖然長度不爲0,可是包含的每一個字符都是空白字符,在trim以後長度爲0。
下面是幾個字符串相關的很經常使用的方法,也是比較通用的概念(都是在字符串指針不爲null的前提下):
isEmpty(): 是否空字符串,即字符串的長度爲0,好比""
isNotEmpty():對isEmpty取反
isBlank():是否空白字符串,即字符串中只有空白字符,好比"\n \r\t"
isNotBlank():對isBlank取反
trim():去除字符串兩邊的空白字符,好比" foo "執行trim以後是"foo",具體請見:Java筆記之java.lang.String#trim
trimToEmpty():返回值要麼是trim()的結果,要麼是空字符串,必定不爲null,好比null—> "", "\n\r" –> ""
trimToNull():某些狀況下不容許爲空字符串,若是爲空的話就認爲是null,可使用此方法直接將一個空白字符串變爲null,好比"\n\r\t" –> null
對於字符串的處理應該儘可能使用Apache commons-lang3或者google guava庫。
爲何要去使用這種開源庫而不是本身造輪子?
一個是知名開源庫會有社區專門去維護,使用羣體比較大,咱們知道當數據量夠大的時候規律就比較明顯,同理使用的人比較多了以後的一個好處是有BUG會被發現的比較快,可能一個新版本的BUG次日就被發現並貼出官方聲明瞭,而本身寫的實現若是沒有人幫review的話可能錯誤只能等出問題的時候才能被發現了。另一個緣由就是知名開源庫由於使用的人比較多,你們有各類好的想法都會提出來去討論應用到這上面,運用集體智慧不斷的去完善、優化它,不論是API的設計仍是實現上都會比本身一我的想出來要好一些。
固然硬要擡槓的話總能找到反例,以前碰到過個很奇葩的API實現,就是Apache commons-io的org.apache.commons.io.FileUtils#byteCountToDisplaySize(java.math.BigInteger),代碼貼出來感覺一下:
/** * Returns a human-readable version of the file size, where the input represents a specific number of bytes. * <p> * If the size is over 1GB, the size is returned as the number of whole GB, i.e. the size is rounded down to the * nearest GB boundary. * </p> * <p> * Similarly for the 1MB and 1KB boundaries. * </p> * * @param size the number of bytes * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes) * @see <a href="https://issues.apache.org/jira/browse/IO-226">IO-226 - should the rounding be changed?</a> * @since 2.4 */ // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed? public static String byteCountToDisplaySize(final BigInteger size) { String displaySize; if (size.divide(ONE_EB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(ONE_EB_BI)) + " EB"; } else if (size.divide(ONE_PB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(ONE_PB_BI)) + " PB"; } else if (size.divide(ONE_TB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(ONE_TB_BI)) + " TB"; } else if (size.divide(ONE_GB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(ONE_GB_BI)) + " GB"; } else if (size.divide(ONE_MB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(ONE_MB_BI)) + " MB"; } else if (size.divide(ONE_KB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(ONE_KB_BI)) + " KB"; } else { displaySize = String.valueOf(size) + " bytes"; } return displaySize; }
BigInteger的整除把1.9M算成1M我忍了,1.9T算成1T這種實在沒辦法忍差太多了…
這個實現你們看了都說很差,不少年了做者也沒改,對於這種狀況也沒什麼好辦法…
.