在通读整片源码前先来了解其中的两个内部类,这两个内部类才是真正去分解字符串的工人:

处理字符、字符串、正则的接口,此接口的定义实质为策略模式

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开始,找到第一个分隔符然后返回位置,没有找到返回-1public int separatorStart(int start) {//获取分割符长度int separatorLength = separator.length();//记录分割符开始位子int p = start;//调用本类的 toSplit 变量即被分割的字符串长度,last取被分割的字符串长度与分割符的差值//分割符号”,” 被分割字符串”a,b,c,d” last= 7-1 = 6int 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值赋值给变量

Guava源码解析五:Splitter源码解析相关推荐

  1. Mybatis-Spring源码分析(五) MapperMethod和MappedStatement解析

    前言 基本上这就是Mybatis-Spring源码的最后一篇了,如果想起来什么再单开博客.比起来Spring源码,Mybatis的确实简单一些,本篇就说一下Mybatis中两个十分重要的类Mapper ...

  2. java解析五元组_pcap文件解析,并且按照五元组分类

    [实例简介] pcap文件解析,并按照五元组分包,全部用java语言实现. [实例截图] [核心代码] PcapTestZZ ├── PcapTestZ │   ├── 111.206.37.1930 ...

  3. cartographer 源码解析 (五)

    相关链接: cartographer 源码解析(一) cartographer 源码解析(二) cartographer 源码解析(三) cartographer 源码解析(四) cartograph ...

  4. (Nacos源码解析五)Nacos服务事件变动源码解析

    Nacos源码解析系列目录 Nacos 源码编译运行 (Nacos源码解析一)Nacos 注册实例源码解析 (Nacos源码解析二)Nacos 服务发现源码解析 (Nacos源码解析三)Nacos 心 ...

  5. Spring源码深度解析,Spring源码以及Bean的生命周期(五)(附代码示例:)

    五)Bean 的生命周期,创建---初始化---销毁的过程 目录 五)Bean 的生命周期,创建---初始化---销毁的过程 一 ,  指定初始化方法 init-method 方法​ 二 ,指定销毁 ...

  6. Tomcat源码解析五:Tomcat请求处理过程

    前面已经分析完了Tomcat的启动和关闭过程,本篇就来接着分析一下Tomcat中请求的处理过程. 在开始本文之前,咋们首先来看看一个Http请求处理的过程,一般情况下是浏览器发送http请求-> ...

  7. 源码解析:Spring源码解析笔记(五)接口设计总览

    本文由colodoo(纸伞)整理 QQ 425343603 Java学习交流群(717726984) Spring解析笔记 启动过程部分已经完成,对启动过程源码有兴趣的朋友可以作为参考文章. 源码解析 ...

  8. SpringBoot各类型参数解析原理(源码)

    上次那篇我们只分析了doDispatch中的getHandler方法(获取执行链,执行链里包括当前请求URL对应的 handler 以及拦截器(Controller.method绑定关系)),今儿继续 ...

  9. Spring源码解析:自定义标签的解析过程

    2019独角兽企业重金招聘Python工程师标准>>> spring version : 4.3.x Spring 中的标签分为默认标签和自定义标签两类,上一篇我们探究了默认标签的解 ...

  10. mybatis源码阅读(五) ---执行器Executor

    转载自  mybatis源码阅读(五) ---执行器Executor 1. Executor接口设计与类结构图 public interface Executor {ResultHandler NO_ ...

最新文章

  1. gdi 中发生一般性错误_SMC/SMD波峰焊接过程中的注意事项分析
  2. 【论文】基于特定实体的文本情感分类总结(PART III)
  3. React Native – 使用 JavaScript 开发原生应用
  4. 如何使用数据卷在宿主机和docker容器之间共享文件
  5. 用 pyecharts 制作数据可视化大屏之数据地图
  6. lombok报错Ambiguous method call. Both
  7. 网络模块与RJ45水晶头接线方法
  8. HTML内嵌内联外联——它们之间的优先级如何?
  9. arch Linux更新添加源,Arch Linux 更新源(以清华 arch 源为例)
  10. 阿里云ECS服务器配置全攻略
  11. matlab三相触发电路图,三相过零触发电路图
  12. MATLAB 2016a系统错误解决方案
  13. 北京车牌那么难摇为什么还能那么受欢迎?
  14. html中怎么设置渐变颜色设置,css中渐变色怎么设置
  15. CMN_1022: [FreeTDS][SQL Server]The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION
  16. Android中添加思源字体/NotoSansCJK/SourceHanSans
  17. winbox添加dhcp和nat
  18. matlab_矩阵和数组
  19. 设计模式-简单工厂模式(SimpleFactory)
  20. 解压缩文件:压缩(zipped)文件夹错误,拒绝访问

热门文章

  1. 在线图片尺寸修改 生成图标
  2. Python 决策树计算熵、gini系数、误分率
  3. C语言实验——拍皮球 1184
  4. python根据生日自动批量产生中奖双色球
  5. Vi IMproved
  6. 【重要】国庆节快乐!有三AI所有课程限时7天优惠
  7. android内存dump分析,闭眼能敲,Android内存分析command
  8. 我的美国CS面试经验分享
  9. python交互式怎么保存_如何保存一个Python交互式会话?
  10. notepad++ paste data vertically