一、背景
不管是公司的项目,还是个人的日常练习,都会使用 org.apache.commons.lang3.StringUtils 这个String工具类,究其原因,是太好用了,而且太全了。比如判断是否为空,截取,拼接之类的。一直没有仔细的看过它的源码,今天我就研究一番,同时作为我“阅读源码”路上的第一步。
二、常用API
注:本次是基于commons-lang3-3.8.1 进行阅读分析总结的,其他版本与此相差不多。
2.0、概念释义
2.0.1、null,empty,space的区别
null:代表无效数据,调用其他Api会有NPE异常;
empty:是有效数据,表示一个长度为0的字符串——"";
space:是有效数据,表示一个长度不为0,但是没有任何内容的字符串——“ ”,其trim后和empty是等价的;
2.0.2、什么是CharSequence
查看StringUtils的源码,你会发现它的方法参数里面经常会出现一个类型:CharSequence。所以有必要在这里解释一下。
CharSequence是一个描述字符串结构的接口,它的常用方法有length(),charAt(),toString 。很熟悉对吧。它的常见实现类有String,StringBuffer,StringBuilder。只要有字符串就可以为CharSequence实例化。
public interface CharSequence { int length(); char charAt(int index); public String toString();
//字符串截取 CharSequence subSequence(int start,int end);
public default IntStream chars() {
//默认逻辑
}
public default IntStream codePoints() {
//默认逻辑
} }
//String public final class String implements java.io.Serializable, Comparable<String>, CharSequence //StringBuffer public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence //StringBuilder public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
2.1、Empty
2.1.1、isEmpty:检查字符串是 "" 或 null
//源码 public static boolean isEmpty(final CharSequence cs) { return cs == null || cs.length() == 0; }
@Test public void isEmpty_Test() { //true StringUtils.isEmpty(null); //true StringUtils.isEmpty(""); //false StringUtils.isEmpty(" "); //false StringUtils.isEmpty("bob"); //false StringUtils.isEmpty(" bob "); }
2.1.2、isNotEmpty:与isEmpty正好相反,判断不为""且不为null
//源码 public static boolean isNotEmpty(final CharSequence cs) { return !isEmpty(cs); }
@Test public void isNotEmpty_Test() { //false StringUtils.isNotEmpty(null); //false StringUtils.isNotEmpty(""); //true StringUtils.isNotEmpty(" "); //true StringUtils.isNotEmpty("bob"); //true StringUtils.isNotEmpty(" bob "); }
2.1.3、isAnyEmpty
2.1.4、isNoneEmpty
2.1.5、isAllEmpty
2.2、Blank
2.2.1、isBlank:检查一个字符串是 "",或null,或只有空格
与isEmpty相比,对于“ ”,isEmpty(" ") =false,isBlank(" ") =true,
//源码 public static boolean isBlank(final CharSequence cs) { int strLen; if (cs == null || (strLen = cs.length()) == 0) { return true; } for (int i = 0; i < strLen; i++) { if (!Character.isWhitespace(cs.charAt(i))) { return false; } } return true; }
@Test public void isBlank_Test() { //true StringUtils.isBlank(null); //true StringUtils.isBlank(""); //true StringUtils.isBlank(" "); //false StringUtils.isBlank("bob"); //false StringUtils.isBlank(" bob "); }
2.2.2、isNotBlank:检查一个字符串不是 "",且不是null,且不只有空格
@Test public void isNotBlank_Test() { //false StringUtils.isNotBlank(null); //false StringUtils.isNotBlank(""); //false StringUtils.isNotBlank(" "); //true StringUtils.isNotBlank("bob"); //true StringUtils.isNotBlank(" bob "); }
2.2.3、isAnyBlank
2.2.4、isNoneBlank
2.2.5、isAllBlank
2.3、Trim
2.3.1、trim:移除字符串两端的空字符串
//源码 public static String trim(final String str) { return str == null ? null : str.trim(); }
@Test public void trim_Test() { //null StringUtils.trim(null); //"" StringUtils.trim(""); //"" StringUtils.trim(" "); //"abc" StringUtils.trim("abc"); //"abc" StringUtils.trim(" abc "); }
2.3.2、trimToNull:trim之后,用isEmpty进行了判断,如果true返回null,否则返回trim后的值
//源码 public static String trimToNull(final String str) { final String ts = trim(str); return isEmpty(ts) ? null : ts; }
StringUtils.trimToNull(null) = null StringUtils.trimToNull("") = null StringUtils.trimToNull(" ") = null StringUtils.trimToNull("abc") = "abc" StringUtils.trimToNull(" abc ") = "abc"
2.3.3、trimToEmpty:如果为null,返回“”,否则返回trim后的值
//源码 public static String trimToEmpty(final String str) { return str == null ? EMPTY : str.trim(); }
StringUtils.trimToEmpty(null) = "" StringUtils.trimToEmpty("") = "" StringUtils.trimToEmpty(" ") = "" StringUtils.trimToEmpty("abc") = "abc" StringUtils.trimToEmpty(" abc ") = "abc"
2.4、Truncate
2.4.1、truncate:字符串截取,从索引为0处截取,截取固定的长度
//源码 public static String truncate(final String str, final int maxWidth) { return truncate(str, 0, maxWidth); }
StringUtils.truncate(null, 0) = null StringUtils.truncate(null, 2) = null StringUtils.truncate("", 4) = "" StringUtils.truncate("abcdefg", 4) = "abcd" StringUtils.truncate("abcdefg", 6) = "abcdef" StringUtils.truncate("abcdefg", 7) = "abcdefg" StringUtils.truncate("abcdefg", 8) = "abcdefg" StringUtils.truncate("abcdefg", -1) = throws an IllegalArgumentException
可以看到,对于起始截取索引,截取长度为负数时,直接报异常;然后被截取字符串为null时,返回null;截取索引大于字符串长度时,返回“”。
//源码 public static String truncate(final String str, final int offset, final int maxWidth) { if (offset < 0) { throw new IllegalArgumentException("offset cannot be negative"); } if (maxWidth < 0) { throw new IllegalArgumentException("maxWith cannot be negative"); } if (str == null) { return null; } if (offset > str.length()) { return EMPTY; } if (str.length() > maxWidth) { final int ix = offset + maxWidth > str.length() ? str.length() : offset + maxWidth; return str.substring(offset, ix); } return str.substring(offset); }
StringUtils.truncate(null, 0, 0) = null StringUtils.truncate(null, 2, 4) = null StringUtils.truncate("", 0, 10) = "" StringUtils.truncate("", 2, 10) = "" StringUtils.truncate("abcdefghij", 0, 3) = "abc" StringUtils.truncate("abcdefghij", 5, 6) = "fghij" StringUtils.truncate("raspberry peach", 10, 15) = "peach" StringUtils.truncate("abcdefghijklmno", 0, 10) = "abcdefghij" StringUtils.truncate("abcdefghijklmno", -1, 10) = throws an IllegalArgumentException StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, 10) = "abcdefghij" StringUtils.truncate("abcdefghijklmno", Integer.MIN_VALUE, Integer.MAX_VALUE) = "abcdefghijklmno" StringUtils.truncate("abcdefghijklmno", 0, Integer.MAX_VALUE) = "abcdefghijklmno" StringUtils.truncate("abcdefghijklmno", 1, 10) = "bcdefghijk" StringUtils.truncate("abcdefghijklmno", 2, 10) = "cdefghijkl" StringUtils.truncate("abcdefghijklmno", 3, 10) = "defghijklm" StringUtils.truncate("abcdefghijklmno", 4, 10) = "efghijklmn" StringUtils.truncate("abcdefghijklmno", 5, 10) = "fghijklmno" StringUtils.truncate("abcdefghijklmno", 5, 5) = "fghij" StringUtils.truncate("abcdefghijklmno", 5, 3) = "fgh" StringUtils.truncate("abcdefghijklmno", 10, 3) = "klm" StringUtils.truncate("abcdefghijklmno", 10, Integer.MAX_VALUE) = "klmno" StringUtils.truncate("abcdefghijklmno", 13, 1) = "n" StringUtils.truncate("abcdefghijklmno", 13, Integer.MAX_VALUE) = "no" StringUtils.truncate("abcdefghijklmno", 14, 1) = "o" StringUtils.truncate("abcdefghijklmno", 14, Integer.MAX_VALUE) = "o" StringUtils.truncate("abcdefghijklmno", 15, 1) = "" StringUtils.truncate("abcdefghijklmno", 15, Integer.MAX_VALUE) = "" StringUtils.truncate("abcdefghijklmno", Integer.MAX_VALUE, Integer.MAX_VALUE) = "" StringUtils.truncate("abcdefghij", 3, -1) = throws an IllegalArgumentException StringUtils.truncate("abcdefghij", -2, 4) = throws an IllegalArgumentException
2.5、Strip
2.5.1、strip
2.5.2、stripToNull
2.5.3、StripToEmpty
2.5.4、stripStart
//null System.out.println(StringUtils.stripStart(null,"xyzbca")); //"" System.out.println(StringUtils.stripStart("","xyzbca")); //"abc " String s1 = StringUtils.stripStart("abc ",null); System.out.println(s1+","+s1.length()); //**abc ** String s2 = StringUtils.stripStart( " abc ",null); System.out.println("**"+s2+"**"); //** abc ** String s3 = StringUtils.stripStart(" abc ",""); System.out.println("**"+s3+"**"); //bc String s4 = StringUtils.stripStart("abc", "a"); System.out.println(s4); //bcysz String s5 = StringUtils.stripStart("xyabcysz","yax"); System.out.println(s5)
//源码 public static String stripStart(final String str, final String stripChars) { int strLen; if (str == null || (strLen = str.length()) == 0) { return str; } int start = 0; if (stripChars == null) { while (start != strLen && Character.isWhitespace(str.charAt(start))) { start++; } } else if (stripChars.isEmpty()) { return str; } else { while (start != strLen && stripChars.indexOf(str.charAt(start)) != -1) { start++; } } return str.substring(start);
}
2.5.5、stripEnd
//源码 public static String stripEnd(final String str, final String stripChars) { int end; if (str == null || (end = str.length()) == 0) { return str; } if (stripChars == null) { while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) { end--; } } else if (stripChars.isEmpty()) { return str; } else { while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) { end--; } } return str.substring(0, end);
}