本文是对 Guava 中 Joiner 的学习介绍。欢迎加入学习项目: LearningGuava。

使用示例

以下参考:官方文档。

开发过程中,用分隔符连接字符串序列可能是一个比较繁琐的过程,但本不应该如此。Joiner 可以简化这个操作。

如果序列中包含 null 值,那么可以使用 Joiner 跳过 null 值:

    // 跳过 null 值result = Joiner.on("; ").skipNulls().join("Harry", null, "Ron", "Hermione");Assert.assertEquals(result, "Harry; Ron; Hermione");

也可以通过 useForNull(String) 来将 null 值替换为指定的字符串。

    // 替换 null 值result = Joiner.on("; ").useForNull("null").join("Harry", null, "Ron", "Hermione");Assert.assertEquals(result, "Harry; null; Ron; Hermione");

同样可以在对象上使用 Joiner,最终会调用对象的 toString() 方法。

    // 使用在对象上,会调用对象的 toString() 函数result = Joiner.on(",").join(Arrays.asList(1, 5, 7));Assert.assertEquals(result, "1,5,7");

对于 Map ,可以使用这样的代码:

    // MapJoiner 的使用,将 map 转换为字符串Map map = ImmutableMap.of("k1", "v1", "k2", "v2");result = Joiner.on("; ").withKeyValueSeparator("=").join(map);Assert.assertEquals(result, "k1=v1; k2=v2");

源码分析

以下参考:Guava 是个风火轮之基础工具(1)。

初始化方法

Joiner 的构造方法被设置成了私有,需要通过静态的 on(String separator) 或者 on(char separator) 函数初始化。

拼接基本函数

Joiner 了中最为核心的函数就是 <A extends Appendable> A appendTo(A appendable, Iterator<?> parts)。作为全功能函数,其它所有的字符串拼接最终都会调用这个函数。

  public <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {checkNotNull(appendable);if (parts.hasNext()) {appendable.append(toString(parts.next()));while (parts.hasNext()) {appendable.append(separator);appendable.append(toString(parts.next()));}}return appendable;}

这段代码的分析如下:
* 这里的 Appendable 源码中传入的是实现该接口的 StringBuilder
* 因为是公共方法,无法保证 appendable 值不为空,所以要先检查该值是否为空。
* if ... while ... 的结构确保末尾不会添加多余的分隔符。
* 通过本地 toString 方法,而不是直接调用对象的 toString 方法,这种做法提供了空指针保护。

不可能发生的异常

在源码中,有个地方的处理值得关注一下:

   public StringBuilder appendTo(StringBuilder builder, Iterator<? extends Entry<?, ?>> entries) {try {appendTo((Appendable) builder, entries);} catch (IOException impossible) {throw new AssertionError(impossible);}return builder;}

这里之所以 IOException 的变量名取名为 impossible 是因为:虽然 Appendable 接口的 append 方法会抛出 IOException,但是传入的 StringBuilder 在实现的时候并不会抛出改异常,所以为了适应这个接口,这里不得不捕捉异常。这样捕捉后的断言处理也就可以理解了。

巧妙的可变长参数转换

有一个添加的重载函数如下所示:

 public final <A extends Appendable> A appendTo(A appendable, @NullableDecl Object first, @NullableDecl Object second, Object... rest)throws IOException {
    return appendTo(appendable, iterable(first, second, rest));}

其中 iterable 函数将参数变为一个可以迭代的序列,该函数如下所示。

private static Iterable<Object> iterable(final Object first, final Object second, final Object[] rest) {checkNotNull(rest);return new AbstractList<Object>() {@Overridepublic int size() {return rest.length + 2;}@Overridepublic Object get(int index) {switch (index) {case 0:return first;case 1:return second;default:return rest[index - 2];}}};}

通过实现 AbstractList 的方式,巧妙地复用了编译器生成的数组,减少了对象创建的开销。这样的实现需要对迭代器有深入的了解,因为要确保实现能够满足迭代器接口各个函数的语义。

Joiner 二次创建

因为 Joiner 创建后就是不可更改的了,所以为了实现 useForNullskipNulls 等语义,源码会再次创建一个匿名类,并覆盖相应的方法。

useForNull 函数汇中为了防止重复调用 useForNullskipNulls,还特意覆盖了这两个方法,一旦调用就抛出运行时异常。为什么不能重复调用 useForNull ?因为覆盖了 toString 方法,而覆盖实现中需要调用覆盖前的 toString

  public Joiner useForNull(final String nullText) {checkNotNull(nullText);return new Joiner(this) {@OverrideCharSequence toString(@NullableDecl Object part) {return (part == null) ? nullText : Joiner.this.toString(part);}@Overridepublic Joiner useForNull(String nullText) {throw new UnsupportedOperationException("already specified useForNull");}@Overridepublic Joiner skipNulls() {throw new UnsupportedOperationException("already specified useForNull");}};}

skipNulls 函数实现如下所示。个人比较奇怪的是 skipNulls 中为什么不禁止重复调用 skipNulls 函数。

  public Joiner skipNulls() {return new Joiner(this) {@Overridepublic <A extends Appendable> A appendTo(A appendable, Iterator<?> parts) throws IOException {checkNotNull(appendable, "appendable");checkNotNull(parts, "parts");while (parts.hasNext()) {Object part = parts.next();if (part != null) {appendable.append(Joiner.this.toString(part));break;}}while (parts.hasNext()) {Object part = parts.next();if (part != null) {appendable.append(separator);appendable.append(Joiner.this.toString(part));}}return appendable;}@Overridepublic Joiner useForNull(String nullText) {throw new UnsupportedOperationException("already specified skipNulls");}@Overridepublic MapJoiner withKeyValueSeparator(String kvs) {throw new UnsupportedOperationException("can't use .skipNulls() with maps");}};}

Guava学习之Joiner相关推荐

  1. 借Google Guava学习发现和开发通用功能模块

    如何发现通用的功能模块? 很多人觉得做业务开发没有挑战,实际上,做业务开发也会涉及很多非业务功能的开发,比如我们前面讲到的 ID 生成器.性能计数器.EventBus.DI 容器,以及后面会讲到的限流 ...

  2. Guava学习笔记:简化异常处理的Throwables类

    Guava学习笔记:简化异常处理的Throwables类 参考文章: (1)Guava学习笔记:简化异常处理的Throwables类 (2)https://www.cnblogs.com/peida/ ...

  3. Google guava学习

    文章目录 Google guava学习 一.摘要 二.优点 三.maven依赖 四.Guava API使用教程 五.GuavaCache本地内存缓存 六.布隆过滤器 Google guava学习 一. ...

  4. Google Guava学习笔记——基础工具类Joiner的使用

    Guava 中有一些基础的工具类,如下所列: 1,Joiner 类:根据给定的分隔符把字符串连接到一起.MapJoiner 执行相同的操作,但是针对 Map 的 key 和 value. 2,Spli ...

  5. Guava学习笔记(转)

    Guava(瓜娃)学习笔记 Guava工程包含了若干被google的java项目广泛依赖的核心库,例如:集合 [collections] .缓存 [caching] .原生类型支持 [primitiv ...

  6. Guava学习笔记:缘起

    缘起 为什么要使用Guava呢?因为在几年前就是用过Guava的部分功能,当时有一个项目需要通过缓存来提升部分功能的性能,对本地应用缓存和分布式应用缓存进行了相关的调研,在调研本地应用缓存的时候,第一 ...

  7. Guava学习笔记:EventBus(转)

    EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现.对于事件监听和发布订阅模式,EventBus是一个非常优雅和简单解决方案,我们不用创建复杂的类和 ...

  8. Guava学习笔记:Google Guava 类库简介

    Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency libra ...

  9. Guava学习笔记 6. 字符串处理[Strings]

    非常有用的字符串工具,包括分割.连接.填充等操作 本文简单介绍了一下Guava的一些字符串工具 本文参考自: http://ifeve.com/google-guava-strings/ 并添加了一些 ...

最新文章

  1. Design Pattern – Separated Interface Pattern[转]
  2. 原文翻译:关于机器学习,我们忽视的东西
  3. android通过webservice连接SQL数据库(一)服务器端
  4. windows终止处理程序( __try __finally) 简单解析
  5. 玩转mini2440开发板之【如何设置开发板的网络参数】
  6. PyTorch Tutorial
  7. linux find查找文件然后删除,linu查找find命令及删除7天前的文件
  8. partial关键字的含义和使用
  9. about x86 protected mode
  10. pandas官方中文手册pdf下载
  11. 普林斯顿微积分读本03第二章--编程实现函数图像绘制、三角学回顾
  12. 3V升压5V芯片,3V升压5V电路图
  13. mysql mpm_mysql监控工具:zabbix+MPM(Performance Monitor for MySQL)
  14. php没有错误信息,php – 如何调试没有错误信息的错误?
  15. 基于springboot电影购票管理系统
  16. 小弟为共享软件作者制作的管理软件注册的动态链接库 (转)
  17. ovation系统服务器安装,OVATION系统
  18. ognl表达式中%{}的作用
  19. AT指令EGMR-修改设备的IMEI号码
  20. 比你聪明的人比你y更聪明

热门文章

  1. 一招连环追销,让顾客在第一次成交中买多个产品,客单价提高十倍
  2. 来公司必须了解的编码开发规范
  3. WoShop跨境电商国际支付Paypal支付商城全开源无加密商城源码
  4. 哈工大SCIR出品《自然语言处理》新书,无套路送5本!
  5. 课堂纪律一团糟老师应该怎么办?
  6. java 写出到文件
  7. APP爬虫之央视新闻
  8. Windows直接拖拽文件复制到虚拟机Ubuntu
  9. 【转载】破解物联网落地困境-阿里云硬件接入最佳实践
  10. 二维码和条形码简单实现