Splitter 的实现中有十分明显的策略模式和模板模式,各种的的方法覆盖,还有 Guava 中的迭代技巧和惰性计算。

成员变量
Splitter 类中4 个成员变量分别所代表的含义:

CharMatcher trimmer:用于描述删除拆分结果的前后指定字符的策略。
boolean omitEmptyStrings:用于控制是否删除拆分结果中的空字符串。
Strategy strategy:用于帮助实现策略模式。
int limit:用于控制拆分的结果个数。
Splitter中的策略模式
Splitter 可以根据字符、字符串、正则、长度还有 Guava 自己的字符匹配器 CharMatcher 来拆分字符串,基本上每种匹配模式的查找方法都不太一样,但是字符拆分的基本框架又是不变的,所以策略模式正好合用。

对于Splitter 策略接口的定义很简单,传入的是一个 Splitter 和一个待拆分的字符串,返回一个迭代器。

private interface Strategy {
Iterator iterator(Splitter splitter, CharSequence toSplit);
}

惰性迭代器与模板模式
惰性计算目的是最小化计算机要做的工作,即把计算推迟到不得不算的时候进行。Guava 中的迭代器使用了惰性计算的技巧,它不是一开始就算好结果放在列表或集合中,而是在调用 hasNext 方法判断迭代是否结束时才去计算下一个元素。

AbstractIterator
以Splitter on(final CharMatcher separatorMatcher)为例

public static Splitter on(final CharMatcher separatorMatcher) {
checkNotNull(separatorMatcher);

return new Splitter(new Strategy() {@Override public SplittingIterator iterator(Splitter splitter, final CharSequence toSplit) {return new SplittingIterator(splitter, toSplit) {@Override int separatorStart(int start) {return separatorMatcher.indexIn(toSplit, start);}@Override int separatorEnd(int separatorPosition) {return separatorPosition + 1;}};}
});

}

这里返回的SplittingIterator继承了AbstractIterator,而AbstractIterator是Iterator的实现类,AbstractIterator 使用私有的枚举变量 state 来记录当前的迭代进度,比如是否找到了下一个元素,迭代是否结束等。AbstractIterator 有一个抽象方法 computeNext,负责计算下一个元素。由于 state 是私有变量,而迭代是否结束只有在调用 computeNext 的过程中才知道,于是提供了一个保护的 endOfData 方法,允许子类将 state 设置为 State.DONE。

private enum State {
READY, NOT_READY, DONE, FAILED,
}

AbstractIterator 实现了迭代器最重要的两个方法,hasNext 和 next。

hasNext 一上来先判断迭代器当前状态,如果已经结束,就返回 false;如果已经找到下一个元素,就返回 true,不然就试着找找下一个元素。

@Override
public final boolean hasNext() {
checkState(state != State.FAILED);
switch (state) {
case READY:
return true;
case DONE:
return false;
default:
}
return tryToComputeNext();
}

next 则是先判断是否还有下一个元素,属于防御式编程,先对自己做保护;然后把状态复原到还没找到下一个元素,然后返回结果。至于把 next 置为 null,可能是帮助 JVM 回收对象。

@Override
public final T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
state = State.NOT_READY;
T result = next;
next = null;
return result;
}eNext();

tryToComputeNext 可以认为是对模板方法 computeNext 的包装调用,首先把状态置为失败,然后才调用 computeNext。这样一来,如果计算下一个元素的过程中发生 RuntimeException,整个迭代器的状态就是 State.FAILED,一旦收到任何调用都会抛出异常。

private boolean tryToComputeNext() {
//保持悲观状态,就是为了保证computeNext()调用出现异常也不影响后面的逻辑
state = State.FAILED;
next = computeNext();
if (state != State.DONE) {
state = State.READY;
return true;
}
return false;
}

AbstractIterator 代码就这些,因为SplittingIterator实现了他的方法,所以要追溯到SplittingIterator。

SplittingIterator
SplittingIterator 还是一个抽象类,虽然实现了 computeNext 方法,但是它又定义了两个虚函数

separatorStart: 返回分隔符在指定下标之后第一次出现的下标
separatorEnd: 返回分隔符在指定下标后面第一个不包含分隔符的下标。
在上面策略模式中可以看到,这两个函数在不同的策略中有各自不同的覆盖实现,在 SplittingIterator 中,这两个函数就是模板函数。

SplittingIterator中核心的函数还是computeNext,这个函数一直在维护的两个内部全局变量:offset和limit。

@Override protected String computeNext() {// 返回的字符串介于上一个分隔符和下一个分隔符之间。// nextStart 是返回子串的起始位置,offset 是下次开启寻找分隔符的地方。int nextStart = offset;while (offset != -1) {int start = nextStart;int end;// 找 offset 之后第一个分隔符出现的位置int separatorPosition = separatorStart(offset);if (separatorPosition == -1) {// 处理没找到的情况end = toSplit.length();offset = -1;} else {// 处理找到的情况end = separatorPosition;offset = separatorEnd(separatorPosition);}// 处理的是第一个字符就是分隔符的特殊情况if (offset == nextStart) {// 发生情况:空字符串 或者 整个字符串都没有匹配。// offset 需要增加来寻找这个位置之后的分隔符,// 但是没有改变接下来返回字符串的 start 的位置,// 所以此时它们二者相同。offset++;if (offset >= toSplit.length()) {offset = -1;}continue;}// 根据 trimmer 来对找到的元素做前处理,比如去除空白符之类的。while (start < end && trimmer.matches(toSplit.charAt(start))) {start++;}// 根据 trimmer 来对找到的元素做后处理,比如去除空白符之类的。while (end > start && trimmer.matches(toSplit.charAt(end - 1))) {end--;}// 根据需要去除那些是空字符串的元素,trim完之后变成空字符串的也会被去除。if (omitEmptyStrings && start == end) {nextStart = offset;continue;}// 判断 limit,if (limit == 1) {end = toSplit.length();// 调整 end 指针的位置标记 offset 为 -1,下一次再调用 computeNext // 的时候就发现 offset 已经是 -1 了,然后就返回 endOfData 表示迭代结束。offset = -1;while (end > start && trimmer.matches(toSplit.charAt(end - 1))) {end--;}} else // 还没到 limit 的极限,就让 limit 自减{limit--;}return toSplit.subSequence(start, end).toString();}return endOfData();
}

}

Guava-Splitter相关推荐

  1. Google Guava Splitter

    String.split的特殊情况 String[] split = ",a,,b,".split(",");for (String s : split) {S ...

  2. guava - Splitter

    在我们使用 java 的split 方法时,如果不是对该方法足够了解,可能会得到我们意想之外的结果.记录下踩过的坑: public void test(){String str = "a,b ...

  3. 三、guava splitter

    splitter工具可以按照分隔符拆分字符串: 示例: package org.example.model;import com.google.common.base.Splitter; import ...

  4. stringutils_番石榴分配器vs StringUtils

    stringutils 因此,我最近写了一篇关于旧的,可靠的Apache Commons StringUtils的文章 ,该文章引起了很多评论,其中之一是Google Guava提供了更好的连接和拆分 ...

  5. 番石榴分配器vs StringUtils

    因此,我最近写了一篇有关旧的,可靠的Apache Commons StringUtils的文章 ,该文章引起了一些评论,其中之一是Google Guava提供了更好的连接和拆分字符串的机制. 我必须承 ...

  6. 如何在Java中分割字符串

    我有一个字符串"004-034556" ,我想分成两个字符串: string1="004"; string2="034556"; 这意味着第 ...

  7. Python 编程中常用的12种基础知识总结

    Python 编程中常用的12 种基础知识总结:正则表达式替换,遍历目录方法,列表按列排序.去重,字典排序,字典.列表.字符串互转,时间对象操作,命令行参数解析(getopt),print 格式化输出 ...

  8. Guava入门~Splitter

    String.split()问题:中间保留,最后丢弃 String commaSeparatedString = "Foo,,Bar,,Baz,,,"; String[] word ...

  9. guava的String之Splitter

    1.常用方法 摘自官网的部分常用方法说明. Base Factories Method Description Example Splitter.on(char) Split on occurrenc ...

  10. guava 字符串操作 Splitter

    withKeyValueSeparator 按照 逗号拆分字符串,按照井号拆分k-v String json = "A=1,B=3"; Map<String,String&g ...

最新文章

  1. python求平方根的代码_Python求平方根(附带源码)
  2. Ueditor和CKeditor 两款编辑器的使用与配置
  3. WIN2000 Apache php mysql 安装及安全手册
  4. 深度学习之基于卷积神经网络实现服装图像识别
  5. 卸载全部appx应用(包括应用商店)
  6. 比特币 源代码_GitHub遭黑客攻击:窃取数百源码并勒索比特币,数量惊人!
  7. python从数据库取数据 显示字段名_如何在python中将SQL数据库中的字段名放入列表中...
  8. 程序员:我们都在为错误买单!
  9. TensorFlow 实现深度神经网络 —— Denoising Autoencoder
  10. 关于用友财务总账的数据库关系
  11. 【爬虫实战】起点中文网排行榜(XPath)
  12. 腾讯课堂后台扩容和性能优化实战
  13. 传奇手游战神引擎开服教程架设教程工具全套图文教程
  14. C语言 | 什么是ANSI C标准?
  15. IDEA中Tomcat重新加载的几种方式
  16. xctf攻防世界 MISC高手进阶区 3-11
  17. 官方免费的正版Xshell,人人都可以马上拥有
  18. 配置环境变量path
  19. Spring 的自动装配
  20. 电磁波波长越短能量越强_电磁波扫盲篇:频率,波长,速度,温度,能量的关系...

热门文章

  1. fpga控制vga显示彩色图片
  2. Stata实验——计算个股“上海机场“的市场模型和CAPM模型的β值
  3. 为什么说衰老先从血管开始?
  4. 结构光三维重建(二)线结构光三维重建
  5. Overlay网络与物理网络的关系
  6. Tensorflow Serving初体验
  7. VC++ MFC实现的优秀的开源项目
  8. IOS神器-fastlane工具实战-IOS自动化接入应用
  9. java 裁剪图片_java实现的图片裁剪功能示例
  10. 原始数据哪里找?这些网站要用好!200个国内外数据网站大全