定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。在Splitter中就主要使用了这种模式.
基础写法为:
Splitter.on('.').split("a,b,c");
有很多Splitter.on()方法 每个参数不同,但他们都在其中构造了Spliter对象.
WIKI 这里就体现了策略模式,不同的Splitter.on()可以相互替换
例如:
public static Splitter on(final String separator) {
checkArgument(separator.length() != 0, "The separator may not be the empty string.");
if (separator.length() == 1) {
return Splitter.on(separator.charAt(0));
}
//返回Splitter对象
return new Splitter(
//构建Strategy接口,并进行实现
new Strategy() {
@Override
public SplittingIterator iterator(Splitter splitter, CharSequence toSplit) {
//接口方法的实现中又构建了SplittingIterator类
return new SplittingIterator(splitter, toSplit) {
@Override
public int separatorStart(int start) {
int separatorLength = separator.length();
positions:
for (int p = start, last = toSplit.length() - separatorLength; p <= last; p++) {
for (int i = 0; i < separatorLength; i++) {
if (toSplit.charAt(i + p) != separator.charAt(i)) {
continue positions;
}
}
return p;
}
return -1;
}
@Override
public int separatorEnd(int separatorPosition) {
return separatorPosition + separator.length();
}
};
}
});
}
//默认构造方法,传入的基本参数是Strategy接口
private Splitter(Strategy strategy) {
this(strategy, false, CharMatcher.none(), Integer.MAX_VALUE);
}
//构造方法,包含Strategy,是否忽略空字符,是否引入CharMatcher作为分割符,分割结果集最大长度
private Splitter(Strategy strategy, boolean omitEmptyStrings, CharMatcher trimmer, int limit) {
this.strategy = strategy;
this.omitEmptyStrings = omitEmptyStrings;
this.trimmer = trimmer;
this.limit = limit;
}
private interface Strategy {
//在接口中定义了一个方法 返回值是一个Iterator
Iterator iterator(Splitter splitter, CharSequence toSplit);
}
在Strategy接口方法的实现中都是构建了SplittingIterator类
private abstract static class SplittingIterator extends AbstractIterator {
final CharSequence toSplit;
final CharMatcher trimmer;
final boolean omitEmptyStrings;
/**
* Returns the first index in {@code toSplit} at or after {@code start} that contains the
* separator.
*/
abstract int separatorStart(int start);
/**
* Returns the first index in {@code toSplit} after {@code separatorPosition} that does not
* contain a separator. This method is only invoked after a call to {@code separatorStart}.
*/
abstract int separatorEnd(int separatorPosition);
int offset = 0;
int limit;
protected SplittingIterator(Splitter splitter, CharSequence toSplit) {
this.trimmer = splitter.trimmer;
this.omitEmptyStrings = splitter.omitEmptyStrings;
this.limit = splitter.limit;
this.toSplit = toSplit;
}
}
调用split()方法进行切分
public Iterable split(final CharSequence sequence) {
checkNotNull(sequence);
return new Iterable() {
@Override
public Iterator iterator() {
return splittingIterator(sequence);
}
@Override
public String toString() {
return Joiner.on(", ")
.appendTo(new StringBuilder().append('['), this)
.append(']')
.toString();
}
};
}
private Iterator splittingIterator(CharSequence sequence) {
//调用第一部分构建好的接口方法
return strategy.iterator(this, sequence);
}
WIKI 接口方法返回了一个SplittingIterator对象 继承于 AbstractIterator
到此为止没有进行任何拆分操作,最终得到的就是一个对于AbstractIterator类的实现
但怎样拆分呢?
//重写了AbstractIterator类的computeNext()方法
@Override
protected String computeNext() {
/*
* The returned string will be from the end of the last match to the beginning of the next
* one. nextStart is the start position of the returned substring, while offset is the place
* to start looking for a separator.
*/
int nextStart = offset;
while (offset != -1) {
int start = nextStart;
int end;
int separatorPosition = separatorStart(offset);
if (separatorPosition == -1) {
end = toSplit.length();
offset = -1;
} else {
end = separatorPosition;
offset = separatorEnd(separatorPosition);
}
if (offset == nextStart) {
/*
* This occurs when some pattern has an empty match, even if it doesn't match the empty
* string -- for example, if it requires lookahead or the like. The offset must be
* increased to look for separators beyond this point, without changing the start position
* of the next returned substring -- so nextStart stays the same.
*/
offset++;
if (offset > toSplit.length()) {
offset = -1;
}
continue;
}
while (start < end && trimmer.matches(toSplit.charAt(start))) {
start++;
}
while (end > start && trimmer.matches(toSplit.charAt(end - 1))) {
end--;
}
if (omitEmptyStrings && start == end) {
// Don't include the (unused) separator in next split string.
nextStart = offset;
continue;
}
if (limit == 1) {
// The limit has been reached, return the rest of the string as the
// final item. This is tested after empty string removal so that
// empty strings do not count towards the limit.
end = toSplit.length();
offset = -1;
// Since we may have changed the end, we need to trim it again.
while (end > start && trimmer.matches(toSplit.charAt(end - 1))) {
end--;
}
} else {
limit--;
}
return toSplit.subSequence(start, end).toString();
}
return endOfData();
}
}
WIKI 之后在进行遍历时调用computeNext()方法才真正进行拆分
这是其另一个实现 返回的是List
public List splitToList(CharSequence sequence) {
checkNotNull(sequence);
Iterator iterator = splittingIterator(sequence);
List result = new ArrayList<>();
while (iterator.hasNext()) {
result.add(iterator.next());
}
//返回的是只读类
return Collections.unmodifiableList(result);
}
返回值为Map的方法
public Map split(CharSequence sequence) {
Map map = new LinkedHashMap<>();
for (String entry : outerSplitter.split(sequence)) {
Iterator entryFields = entrySplitter.splittingIterator(entry);
checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
String key = entryFields.next();
checkArgument(!map.containsKey(key), "Duplicate key [%s] found.", key);
checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
String value = entryFields.next();
map.put(key, value);
checkArgument(!entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
}
//同样返回的是不可变类
return Collections.unmodifiableMap(map);
}
}
还有很多条件可以选择 这些条件的返回值和on方法一样都是Splitter对象 等于对Splitter的值进行了设置
// 设置omitEmptyString属性而不是想象中的直接忽略,体现懒加载思想
public Splitter omitEmptyStrings() {
return new Splitter(strategy, true, trimmer, limit);
}
//限制拆分器返回的最大项数或者列表的最大长度
public Splitter limit(int limit) {
checkArgument(limit > 0, "must be greater than zero: %s", limit);
return new Splitter(strategy, omitEmptyStrings, trimmer, limit);
}
//返回结果不带前缀和后缀空格
public Splitter trimResults() {
return trimResults(CharMatcher.whitespace());
}
// TODO(kevinb): throw if a trimmer was already specified!
public Splitter trimResults(CharMatcher trimmer) {
checkNotNull(trimmer);
return new Splitter(strategy, omitEmptyStrings, trimmer, limit);
}
当然也有切分成map的情况 返回的是MapSplitter类对象,但其中属性还是两个Splitter对象 通过构成map的两个条件进行两次拆分
public static final class MapSplitter {
private static final String INVALID_ENTRY_MESSAGE = "Chunk [%s] is not a valid entry";
//两个Splitter
private final Splitter outerSplitter;
private final Splitter entrySplitter;
private MapSplitter(Splitter outerSplitter, Splitter entrySplitter) {
this.outerSplitter = outerSplitter; // only "this" is passed
this.entrySplitter = checkNotNull(entrySplitter);
}
public Map split(CharSequence sequence) {
Map map = new LinkedHashMap<>();
//通过第一个Splitter进行第一次拆分
for (String entry : outerSplitter.split(sequence)) {
//进行第二次拆分
Iterator entryFields = entrySplitter.splittingIterator(entry);
checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
String key = entryFields.next();
checkArgument(!map.containsKey(key), "Duplicate key [%s] found.", key);
checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
String value = entryFields.next();
map.put(key, value);
checkArgument(!entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
}
return Collections.unmodifiableMap(map);
}
}
这里的AbstractIterator类是com.google.common.base包下的 , 是com.google.common.collect.AbstractIterator的一个简写
/**
* Note this class is a copy of {@link com.google.common.collect.AbstractIterator} (for dependency
* reasons).
*/
@GwtCompatible
abstract class AbstractIterator implements Iterator {
private State state = State.NOT_READY;
protected AbstractIterator() {}
private enum State {
READY,
NOT_READY,
DONE,
FAILED,
}
private @Nullable T next;
//在splitter类中重写的方法
protected abstract T computeNext();
@CanIgnoreReturnValue
protected final @Nullable T endOfData() {
state = State.DONE;
return null;
}
@Override
public final boolean hasNext() {
checkState(state != State.FAILED);
switch (state) {
case READY:
return true;
case DONE:
return false;
default:
}
return tryToComputeNext();
}
private boolean tryToComputeNext() {
state = State.FAILED; // temporary pessimism
next = computeNext();
if (state != State.DONE) {
state = State.READY;
return true;
}
return false;
}
@Override
public final T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
state = State.NOT_READY;
T result = next;
next = null;
return result;
}
@Override
public final void remove() {
throw new UnsupportedOperationException();
}
}