編碼的世界 / 優質文選 / 生涯

StringUtils在commons-lang3和commons-lang中的區別


2022年3月18日
-   

最近經常需要對String做一些判斷和處理,於是就用到了Apache提供的StringUtils這個工具類,用的時候發現有兩個不同的版本,一個版本位於org.apache.commons.lang下面,另一個則位於org.apache.commons.lang3下面。
查了一下資料,lang3是Apache Commons 團隊發布的工具包,要求jdk版本在1.5以上,相對於lang來說完全支持java5的特性,廢除了一些舊的API。該版本無法兼容舊有版本,於是為了避免沖突改名為lang3。這些東西就不再細說了,我們來看看StringUtils中常用的一些方法有什麼改變吧。
PS.本文的java版本為1.8。

1.isEmpty、isNotEmpty、isBlank、isNotBlank
先貼源碼
 //lang
public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
public static boolean isBlank(String str) {
int strLen;
if(str != null && (strLen = str.length()) != 0) {
for(int i = 0; i < strLen; ++i) {
if(!Character.isWhitespace(str.charAt(i))) {
return false;
}
}
return true;
} else {
return true;
}
}
public static boolean isNotBlank(String str) {
return !isBlank(str);
}

 //lang3
public static boolean isEmpty(CharSequence cs) {
return cs == null || cs.length() == 0;
}
public static boolean isNotEmpty(CharSequence cs) {
return !isEmpty(cs);
}
public static boolean isBlank(CharSequence cs) {
int strLen;
if(cs != null && (strLen = cs.length()) != 0) {
for(int i = 0; i < strLen; ++i) {
if(!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
} else {
return true;
}
}
public static boolean isNotBlank(CharSequence cs) {
return !isBlank(cs);
}

可以看到這幾個方法邏輯毫無變化,只是參數類型變了,由String變為CharSequence。那麼這個CharSequence是什麼呢?我們看看它的源碼:
/**
* A <tt>CharSequence</tt> is a readable sequence of <code>char</code> values. This
* interface provides uniform, read-only access to many different kinds of
* <code>char</code> sequences.
* A <code>char</code> value represents a character in the <i>Basic
* Multilingual Plane (BMP)</i> or a surrogate. Refer to <a
* href="Character.html#unicode">Unicode Character Representation</a> for details.
*
* <p> This interface does not refine the general contracts of the {@link
* java.lang.Object#equals(java.lang.Object) equals} and {@link
* java.lang.Object#hashCode() hashCode} methods. The result of comparing two
* objects that implement <tt>CharSequence</tt> is therefore, in general,
* undefined. Each object may be implemented by a different class, and there
* is no guarantee that each class will be capable of testing its instances
* for equality with those of the other. It is therefore inappropriate to use
* arbitrary <tt>CharSequence</tt> instances as elements in a set or as keys in
* a map. </p>
*
* @author Mike McCloskey
* @since 1.4
* @spec JSR-51
*/
public interface CharSequence {
int length();
char charAt(int index);
CharSequence subSequence(int start, int end);
public String toString();
}

CharSequence是一個字符序列的接口,其中定義了一些常用的如length()、subSequence()等方法,String也實現了這個接口。當然大家可能在String裏用到的都是subString(),實際上String也實現了subSequence()這個方法,只是直接指向了subString()。
//String中的subSequence方法
public CharSequence subSequence(int beginIndex, int endIndex) {
return this.substring(beginIndex, endIndex);
}

lang3中使用CharSequence最大的好處就是令這些方法用處更加廣泛,不止局限於String,其他一些實現了該接口的類也可以使用StringUtils中的這些方法去進行一些操作。另外我發現很多nio中的類都實現了這個接口,個人猜測可能也有為nio服務的目的。
2.equals
//lang
public static boolean equals(String str1, String str2) {
return str1 == null?str2 == null:str1.equals(str2);
}

//lang3
public static boolean equals(CharSequence cs1, CharSequence cs2) {
return cs1 == cs2?true:(cs1 != null && cs2 != null?(cs1.length() != cs2.length()?false:(cs1 instanceof String && cs2 instanceof String?cs1.equals(cs2):CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length()))):false);
}

在lang中,第一步是先判斷str1是否為空,而在lang3中,第一步則是先判斷兩個對象是否相同。這個不難理解,如果兩個對象的地址相同,那麼它們指向的就是同一個對象,內容肯定相同。
3.isAnyEmpty、isNoneEmpty、isAllEmpty
 //lang3
public static boolean isAnyEmpty(CharSequence css) {
if(ArrayUtils.isEmpty(css)) {
return false;
} else {
CharSequence[] var1 = css;
int var2 = css.length;
for(int var3 = 0; var3 < var2; ++var3) {
CharSequence cs = var1[var3];
if(isEmpty(cs)) {
return true;
}
}
return false;
}
}
public static boolean isNoneEmpty(CharSequence css) {
return !isAnyEmpty(css);
}
public static boolean isAllEmpty(CharSequence css) {
if(ArrayUtils.isEmpty(css)) {
return true;
} else {
CharSequence[] var1 = css;
int var2 = css.length;
for(int var3 = 0; var3 < var2; ++var3) {
CharSequence cs = var1[var3];
if(isNotEmpty(cs)) {
return false;
}
}
return true;
}
}

在lang3中,還加入了一些同時判斷多個參數的方法,可以看到實際上是將參數列表放入一個CharSequence數組中,然後遍歷調用之前的isEmpty等方法。判斷blank也有類似的方法。
可能有人會覺得,很多方法String本身就有啊,為什麼還要用StringUtils提供的呢?拋開參數類型不談,我們可以看到,StringUtils中的方法大多都做了空校驗,如果為空時會返回Null或者空串,而String本身的方法在很多傳入參數或對象本身為空的時候都會報空指針錯誤。
常用方法就先介紹到這裏,以後有機會再繼續更。
PS.看CharSequence源碼的時候發現裏面居然有實現了的方法,只是返回值前面加了個default。查了一下發現是Java8的新特性,可以在接口裏面定義default方法,從而使得接口在進行擴展的時候,不會破壞與接口相關的實現類代碼。可以參考Java 8新特性——default方法(defender方法)介紹

熱門文章