在通读整片源码前先来了解其中的两个内部类,这两个内部类才是真正去分解字符串的工人:
处理字符、字符串、正则的接口,此接口的定义实质为策略模式
private interface Strategy {
Iterator<String> iterator(Splitter var1, CharSequence var2);
}
此接口中只有一个方法,返回的是一个Iterator迭代器,这里我们可以先联想到最终返回的集合的迭代器会与它有关系
这里实现了一个惰性迭代器,直到不得不计算的时候才会去将字符串分割,即在迭代的时候才去分割字符串,无论将分隔符还是被分割的字符串加载到Splitter类中,都不会去分割,只有在迭代的时候才会真正的去分割
private abstract static class SplittingIterator extends AbstractIterator<String> {
final CharSequence toSplit;
final CharMatcher trimmer;
final boolean omitEmptyStrings;
int offset = 0;
int limit;
//获取被分割字符串中第一个与分隔符匹配的位置
abstract int separatorStart(int var1);
//获取当前分隔符在字符串中的结尾位置
abstract int separatorEnd(int var1);
//将当前的截取字符串信息赋值给SplittingIterator变量
protected SplittingIterator(Splitter splitter, CharSequence toSplit) {
this.trimmer = splitter.trimmer;
this.omitEmptyStrings = splitter.omitEmptyStrings;
this.limit = splitter.limit;
this.toSplit = toSplit;
}
//重写迭代方法,就是这里实现的懒迭代器
protected String computeNext() {
int nextStart = this.offset;
while(true) {
while(this.offset != -1) {
int start = nextStart;
//根据separatorStart方法进行获取字符串中的第一个分隔符位置
int separatorPosition = this.separatorStart(this.offset);
int end;
if(separatorPosition == -1) {
end = this.toSplit.length();
this.offset = -1;
} else {
end = separatorPosition;
//根据separatorEnd方法进行获取字符串中的第一个分隔符的结束位置
this.offset = this.separatorEnd(separatorPosition);
}
if(this.offset != nextStart) {
while(start < end && this.trimmer.matches(this.toSplit.charAt(start))) {
++start;
}
while(end > start && this.trimmer.matches(this.toSplit.charAt(end - 1))) {
--end;
}
//如果omitEmptyStrings为true,则对空结果跳过处理
if(!this.omitEmptyStrings || start != end) {
//当规定的最多结果数值为1时,输出最后的所有字符串,然后结束迭代
if(this.limit == 1) {
end = this.toSplit.length();
for(this.offset = -1; end > start && this.trimmer.matches(this.toSplit.charAt(end - 1)); --end) {
;
}
} else {
//没有到最后一个时,进行减1操作
--this.limit;
}
return this.toSplit.subSequence(start, end).toString();
}
nextStart = this.offset;
} else {
++this.offset;
if(this.offset > this.toSplit.length()) {
this.offset = -1;
}
}
}
return (String)this.endOfData();
}
}
}
这是一个实现AbstractIterator的一个抽象类,他实现了 computeNext方法(此方法可以在看集合源码的时候多注意一下),这个方法实际上是规定了此迭代器的一个迭代规则。所以Splitter类为他分割完的结果集也写了一个迭代器并规定了自己的迭代规则。从这个迭代器的实现上,在结合Strategy 类便可以讲整个字符串分割的过程给串起来了
变量
//移除指定字符项,即集合中当前元素与trimmer匹配,将其移除。如果没有设置trimmer,则将结果中的空格删除
//最终结论为:将结果集中的每个字符串前缀和后缀都去除trimmer,知道前缀或后缀没有这个字符了,字符串“中”的不用去除
private final CharMatcher trimmer;
//是否移除结果集中的空集,true为移除结果集中的空集,false为不用移除结果集中的空集
private final boolean omitEmptyStrings;
//这个变量最终会返回一个所有集合类的父接口,它是贯穿着整个字符串分解的变量
private final Splitter.Strategy strategy;
//最多将字符串分为几个集合,比如limit=3, 对”a,b,c,d”字符串进行','分割,返回的[”a”,”b”,”c,d”] 意思为最多可以分割成3段,这个可以在链式编程的limit方法参数设置
private final int limit;
构造方法
两个构造函数都是静态构造器,所以不能直接使用这两个构造器去创建Splitter,想要创建Splitter只能使用静态方法。
//接收 一个Strategy类对象
private Splitter(Splitter.Strategy strategy) {
this(strategy, false, CharMatcher.NONE, 2147483647);
}
//此构造器为所有变量进行赋值
private Splitter(Splitter.Strategy strategy, boolean omitEmptyStrings, CharMatcher trimmer, int limit) {
this.strategy = strategy;
this.omitEmptyStrings = omitEmptyStrings;
this.trimmer = trimmer;
this.limit = limit;
}
静态创建Splitter函数
静态创建Splitter函数可以按照4类进行分析(接收字符、字符串、正则表达式的和按指定长度分割构造器):
第一种:接收字符的构造器
//接收一个字符的构造器,然后调用参数为 CharMatcher的构造器
public static Splitter on(char separator) {
return on((CharMatcher)CharMatcher.is(separator));
}
//接收一个CharMatcher的构造器
public static Splitter on(final CharMatcher separatorMatcher) {
//对字符判空
Preconditions.checkNotNull(separatorMatcher);
//返回一个Splitter对象,传入Strategy对象,并对Strategy接口进行实现
return new Splitter(new Splitter.Strategy() {
//实现接口Strategy的iterator方法
public Splitter.SplittingIterator iterator(final Splitter splitter, final CharSequence toSplit) {
//返回 SplittingIterator对象,并对 SplittingIterator 抽象类实现 separatorStart方法和 separatorEnd方法
return new Splitter.SplittingIterator(splitter, toSplit) {
//返回从start开始的第一个分隔符的开始位置
int separatorStart(int start) {
return separatorMatcher.indexIn(this.toSplit, start);
}
//返回当前分割符的末尾位置
int separatorEnd(int separatorPosition) {
return separatorPosition + 1;
}
};
}
});
}
第二种:接收字符串构造器
//传入一个字符串作为分隔符
public static Splitter on(final String separator) {
Preconditions.checkArgument(separator.length() != 0, "The separator may not be the empty string.");
//如果当前字符串的长度为1,则直接调用解析单个字符的构造器上,否则会返回一个Splitter对象,传入Strategy对象,并对Strategy接口进行实现
return separator.length() == 1?on(separator.charAt(0)):new Splitter(new Splitter.Strategy() {
//实现Strategy接口
public Splitter.SplittingIterator iterator(final Splitter splitter, final CharSequence toSplit) {
return new Splitter.SplittingIterator(splitter, toSplit) {
//这个方法是被分割字符串从start开始,找到第一个分隔符然后返回位置,没有找到返回-1
public int separatorStart(int start) {
//获取分割符长度
int separatorLength = separator.length();
//记录分割符开始位子
int p = start;
//调用本类的 toSplit 变量即被分割的字符串长度,last取被分割的字符串长度与分割符的差值
//分割符号”,” 被分割字符串”a,b,c,d” last= 7-1 = 6
int last = this.toSplit.length() - separatorLength;
//找到匹配到分隔符的第一个位置
label23:
while(p <= last) {
for(int i = 0; i < separatorLength; ++i) {
if(this.toSplit.charAt(i + p) != separator.charAt(i)) {
++p;
continue label23;
}
}
return p;
}
return -1;
}
//传入分离器位置,返回分离器末尾位置
public int separatorEnd(int separatorPosition) {
return separatorPosition + separator.length();
}
};
}
});
}
第三种:接收正则表达式构造器
//传入一个字符串,返回一个调用传入CommonPattern类型的on方法
@GwtIncompatible
public static Splitter onPattern(String separatorPattern) {
return on((CommonPattern)Platform.compilePattern(separatorPattern));
}
//传入一个Pattern类型参数,返回一个调用传入CommonPattern类型的on方法
@GwtIncompatible
public static Splitter on(Pattern separatorPattern) {
return on((CommonPattern)(new JdkPattern(separatorPattern)));
}
//传入一个 CommonPattern类型的构造器
private static Splitter on(final CommonPattern separatorPattern) {
Preconditions.checkArgument(!separatorPattern.matcher("").matches(), "The pattern may not match the empty string: %s", separatorPattern);
//返回一个Splitter对象,传入Strategy对象,并对Strategy接口进行实现
return new Splitter(new Splitter.Strategy() {
//实现Strategy对象的iterator方法
public Splitter.SplittingIterator iterator(final Splitter splitter, final CharSequence toSplit) {
final CommonMatcher matcher = separatorPattern.matcher(toSplit);
return new Splitter.SplittingIterator(splitter, toSplit) {
//返回从start开始的第一个分隔符的开始位置
public int separatorStart(int start) {
return matcher.find(start)?matcher.start():-1;
}
//返回当前分割符的末尾位置
public int separatorEnd(int separatorPosition) {
return matcher.end();
}
};
}
});
}
第四种:按指定长度分割的构造器
public static Splitter fixedLength(final int length) {
Preconditions.checkArgument(length > 0, "The length may not be less than 1");
return new Splitter(new Splitter.Strategy() {
public Splitter.SplittingIterator iterator(final Splitter splitter, final CharSequence toSplit) {
return new Splitter.SplittingIterator(splitter, toSplit) {
//按 length长度进行跨步
public int separatorStart(int start) {
int nextChunkStart = start + length;
return nextChunkStart < this.toSplit.length()?nextChunkStart:-1;
}
public int separatorEnd(int separatorPosition) {
return separatorPosition;
}
};
}
});
}
进行分割的函数 (split、splittingIterator)
对分割完字符串后的存储结构可以分为返回值为容器的和List的,分别介绍这两个方法
首先介绍返回值为容器的
public Iterable<String> split(final CharSequence sequence) {
Preconditions.checkNotNull(sequence);
//返回一个容器,然后重写了iterator和toString方法
return new Iterable() {
public Iterator<String> iterator() {
//调用了 splittingIterator方法,以下可以查看 splittingIterator方法的实现
return Splitter.this.splittingIterator(sequence);
}
public String toString() {
return Joiner.on(", ").appendTo((new StringBuilder()).append('['), this).append(']').toString();
}
};
}
以下是 splittingIterator的源码
private Iterator<String> splittingIterator(CharSequence sequence) {
return this.strategy.iterator(this, sequence);
}
这里调用了Strategy的iterator方法,这个方法在on里面有多种的实现方法,所以结合最先的 SplittingIterator类重写的迭代方法,这里就形成了一个特殊的容器返回,真正的拆分字符串动作是在迭代的时候进行的。
在对返回List对象的方法进行解析
public List<String> splitToList(CharSequence sequence) {
Preconditions.checkNotNull(sequence);
Iterator iterator = this.splittingIterator(sequence);
ArrayList result = new ArrayList();
while(iterator.hasNext()) {
result.add(iterator.next());
}
return Collections.unmodifiableList(result);
}
实际上他和上面一样调用了Strategy和SplittingIterator中的方法实现了在迭代时候去分割字符串。只不过他真正的迭代了一边然后将结果集放在了List容器中,与直接抛出一个可迭代的容器各有各的好吧。
其他功能函数
omitEmptyStrings方法
移去结果中的空字符串根据源码说明:
public Splitter omitEmptyStrings() {
return new Splitter(this.strategy, true, this.trimmer, this.limit);
}
这里就是将omitEmptyStrings标记位改为true,在进行输出操作时将空结果略过
trimResults方法
他有两种实现方法:
//将结果中的空格删除
public Splitter trimResults() {
return this.trimResults(CharMatcher.whitespace());
}
//移除指定字符
public Splitter trimResults(CharMatcher trimmer) {
Preconditions.checkNotNull(trimmer);
return new Splitter(this.strategy, this.omitEmptyStrings, trimmer, this.limit);
}
调用此方法可以将结果集中的每个字符串前缀和后缀都去除trimmer,他的实现也是在迭代器中进行的
limit方法
达到指定数目后停止字符串划分
public Splitter limit(int limit) {
Preconditions.checkArgument(limit > 0, "must be greater than zero: %s", limit);
return new Splitter(this.strategy, this.omitEmptyStrings, this.trimmer, limit);
}
将传入的limit值赋值给变量