[源码分析]StringJoiner的使用以及源码分析

StringJoiner是Java里1.8新增的类, 或许有一部分人没有接触过. 所以本文将从使用例子入手, 分析StringJoiner的源码.

基本好的同学, 其实只要把这段例子自己运行一下, 自己看看源码就可以了. 因为我觉得这个类挺简单的. 没必要看我下面的废话....

public class StringJoinerTest {
public static void main(String[] args) {
StringJoiner joiner = new StringJoiner("--", "[[[_", "_]]]");
System.out.println("toString: " + joiner.toString());
System.out.println("length: " + joiner.length()); System.out.println("******************(1)********************"); joiner.add("1");
joiner.add("2");
joiner.add("3");
joiner.add("4");
System.out.println("toString: " + joiner.toString());
System.out.println("length: " + joiner.length()); System.out.println("******************(2)********************"); StringJoiner joiner2 = new StringJoiner("...");
System.out.println("toString: " + joiner2.toString());
System.out.println("length: " + joiner2.length()); System.out.println("******************(3)********************"); joiner2.add("a");
joiner2.add("b");
joiner2.add("c");
System.out.println("toString: " + joiner2.toString());
System.out.println("length: " + joiner2.length()); System.out.println("******************(4)********************"); joiner.merge(joiner2);
System.out.println("toString: " + joiner.toString()); System.out.println("******************(5)********************"); StringJoiner joiner3 = new StringJoiner("==", "qianzhui", "houzhui");
joiner3.add("壹");
joiner3.add("贰");
joiner3.add("叁"); joiner.merge(joiner3);
System.out.println("toString: " + joiner.toString());
System.out.println("length: " + joiner.length()); System.out.println("******************(6)********************");
joiner.merge(joiner); // joiner.merge(this)
System.out.println("toString: " + joiner.toString());
System.out.println("length: " + joiner.length());
}
}

输出结果如下:

toString: [[[__]]]
length: 8
******************(1)********************
toString: [[[_1--2--3--4_]]]
length: 18
******************(2)********************
toString:
length: 0
******************(3)********************
toString: a...b...c
length: 9
******************(4)********************
toString: [[[_1--2--3--4--a...b...c_]]]
******************(5)********************
toString: [[[_1--2--3--4--a...b...c--壹==贰==叁_]]]
length: 38
******************(6)********************
toString: [[[_1--2--3--4--a...b...c--壹==贰==叁--1--2--3--4--a...b...c--壹==贰==叁_]]]
length: 70

上面的例子看懂的同学, 其实没必要往下看下去了....下面的几个例子就当是我自己做了个总结吧.

例1

public class StringJoinerTest2 {
public static void main(String[] args) {
StringJoiner joiner = new StringJoiner("--", "[[[_ ", "_]]]");
System.out.println(joiner.toString());
System.out.println(joiner.length());
}
}

输出结果如下:

这个构造器要传入三个参数. 第一个是`分隔符` , 第二个是`前缀` , 第三个是 `后缀`. 现在不明白也没有关系, 下面待会儿会详细介绍.

咱们先把这个构造器对应的源码看了吧:

先是判断非空. 然后就开始赋值了. emptyValue被赋值为了prefix+suffix . 这段代码就是这么简单... 其中:

1. prefix 是前缀.            (待会儿再讲)

2. delimiter 是分隔符     (待会儿再讲)

3. suffix 是后缀             (待会儿再讲)

4. emptyValue是本类的`空值`. 空值准确来说应该是null, 但StringJoiner类把emptyValue来当空值来处理. (马上就讲)

构造器看完了, 咱们再看看toString方法:

因为目前的代码里, 没有对value进行过赋值操作, 所以value肯定是null. 所以会执行第一个if.

也就是说真正的值value为空的时候, 就会返回本类默认的空值emptyValue. (大家有没有现在应该知道emptyValue的作用了吧)

toString就先分析这一小段if, 剩下的后面再讲. 接下来咱们看看length()方法:

value非空的时候, 长度就是value的长度+后缀的长度.(前缀呢? 前缀去哪儿了? 为什么不单独再加上前缀的长度呢? 带着这个疑惑往下看) .

value为空的时候, 长度就是emptyValue的长度.

例2

咱们往StringJoiner添加 "1"

public class StringJoinerTest2 {
public static void main(String[] args) {
StringJoiner joiner = new StringJoiner("--", "[[[_", "_]]]");
joiner.add("1");
System.out.println("toString: " + joiner.toString());
System.out.println("length: " + joiner.length());
}
}

输出结果如下:

这个时候, 或许大家对`前缀` `后缀` 有些理解了吧. (还没理解也无所谓, 往下看)

咱们看看add方法的源码吧:

通过append方法, 将咱们传入的"1"添加到了末尾. 那么prepareBuilder()方法返回的是什么呢?看看源码吧:

咱们调用add("1")的时候, value为空. 所以会执行else语句. 在这里新实例化了一个StringBuilder. 然后StringBuilder先追加了`前缀`.  (if语句先不讲, 等执行到了再讲)

所以此时prepareBuilder方法返回的value实际上就是前缀: "[[[_"

回到add方法, 刚才咱们说了add方法即时在prepareBuilder返回的值后面追加了"1"而已.

所以执行完add方法之后, value就等于 "[[[_1"    所以value里就已经包含了前缀了. 所以length方法里"为什么不单独再计算前缀的长度呢?" 因为value里面就已经包含前缀了.

咱们再看看toString方法:

这次value非空. 所以执行这里else语句:

如果suffix等于空字符串, 那么就返回value.

如果suffix不等于空字符串, 那么就返回value+后缀.

再看看length()方法:

value不为空, 所以返回的值是 value的长度+后缀的长度.

例3

public class StringJoinerTest2 {
public static void main(String[] args) {
StringJoiner joiner = new StringJoiner("--", "[[[_", "_]]]");
joiner.add("1");
joiner.add("2");
joiner.add("3");
joiner.add("4");
System.out.println("toString: " + joiner.toString());
System.out.println("length: " + joiner.length());
}
}

输出结果如下:

add("1")和上一小节的执行流程一样. 这回看看add("2");的执行流程吧:

由于前面add("1")执行完了, 所以导致value已经不是null了. 所以这里会执行prepareBuilder方法里的if语句. 在value后直接追加一个delimiter分隔符. 然后返回这个value.

然后再add方法里, 把"2"追加到value后面.

例4

咱们发现add方法最后返回的是this.所以上面一小节的示例代码可以写成这样:

public class StringJoinerTest2 {
public static void main(String[] args) {
StringJoiner joiner = new StringJoiner("--", "[[[_", "_]]]");
joiner.add("1").add("2").add("3").add("4");
System.out.println("toString: " + joiner.toString());
System.out.println("length: " + joiner.length());
}
}

例5

StringJoiner还有一个构造器, 只需传入分隔符:

public class StringJoinerTest2 {
public static void main(String[] args) {
StringJoiner joiner2 = new StringJoiner("...");
System.out.println("toString: " + joiner2.toString());
System.out.println("length: " + joiner2.length());
System.out.println("**************************************");
joiner2.add("a");
joiner2.add("b");
joiner2.add("c");
System.out.println("toString: " + joiner2.toString());
System.out.println("length: " + joiner2.length());
}
}

输出结果如下:

构造器源码如下:

就是只指定了分割符, 把前缀和后缀都指定为了空字符串.

例6

接下来咱们看看merge方法

public class StringJoinerTest2 {
public static void main(String[] args) {
StringJoiner joiner = new StringJoiner("--", "[[[_", "_]]]");
joiner.add("1").add("2").add("3").add("4"); StringJoiner joiner2 = new StringJoiner("...");
joiner2.add("a").add("b").add("c"); joiner.merge(joiner2);
System.out.println(joiner.toString());
}
}

输出结果如下:

merge的源代码如下:

咱们看到了用append方法进行了字符串追加. (append的时候刨除去了other.value 的前缀).

总结

1. prepareBuilder方法在value为空的时候, 给value加上前缀.

2. prepareBuilder方法在value非空的时候, 给value加上分隔符.

3. 很多方法都不能传入null为参数. 因为用Objects.requireNonNul方法限定了.

4. 前缀是包含在value里的. 而后缀部分是toString的时候才会被临时添加到value里.

[源码分析]Java1.8中StringJoiner的使用以及源码分析的更多相关文章

  1. 【测试】通过SYS用户,对SCOTT用户的会话进行跟踪,并分析此会话中性能消耗较高的SQL,分析并给出优化建议。

    ①连接到scott下,查询scott对应的sid,serial# SQL> select sid,serial#,username from v$session where username=' ...

  2. angular源码分析:angular中脏活累活的承担者之$interpolate

    一.首先抛出两个问题 问题一:在angular中我们绑定数据最基本的方式是用两个大括号将$scope的变量包裹起来,那么如果想将大括号换成其他什么符号,比如换成[{与}],可不可以呢,如果可以在哪里配 ...

  3. angular源码分析:angular中入境检察官$sce

    一.ng-bing-html指令问题 需求:我需要将一个变量$scope.x = '<a href="http://www.cnblogs.com/web2-developer/&qu ...

  4. angular源码分析:angular中各种常用函数,比较省代码的各种小技巧

    angular的工具函数 在angular的API文档中,在最前面就是讲的就是angular的工具函数,下面列出来 angular.bind //用户将函数和对象绑定在一起,返回一个新的函数 angu ...

  5. angular源码分析:angular中的依赖注入式如何实现的

    一.准备 angular的源码一份,我这里使用的是v1.4.7.源码的获取,请参考我另一篇博文:angular源码分析:angular源代码的获取与编译环境安装 二.什么是依赖注入 据我所知,依赖注入 ...

  6. MapReduce中map并行度优化及源码分析

    mapTask并行度的决定机制 一个job的map阶段并行度由客户端在提交job时决定,而客户端对map阶段并行度的规划的基本逻辑为:将待处理数据执行逻辑切片(即按照一个特定切片大小,将待处理数据划分 ...

  7. 【转】【java源码分析】Map中的hash算法分析

    全网把Map中的hash()分析的最透彻的文章,别无二家. 2018年05月09日 09:08:08 阅读数:957 你知道HashMap中hash方法的具体实现吗?你知道HashTable.Conc ...

  8. RocketMQ中Broker的HA策略源码分析

    Broker的HA策略分为两部分①同步元数据②同步消息数据 同步元数据 在Slave启动时,会启动一个定时任务用来从master同步元数据 if (role == BrokerRole.SLAVE) ...

  9. 鸿蒙内核源码分析(编译脚本篇) | 如何防编译环境中的牛皮癣 | 百篇博客分析OpenHarmony源码 | v58.01

    百篇博客系列篇.本篇为: v58.xx 鸿蒙内核源码分析(环境脚本篇) | 编译鸿蒙原来如此简单 | 51.c.h.o 本篇用两个脚本完成鸿蒙(L1)的编译环境安装/源码下载/编译过程,让编译,调试鸿 ...

随机推荐

  1. 基于Netty 实现简单的私有协议

    原文链接 基于Netty 实现简单的私有协议 代码仓库地址 基于Netty 实现简单的私有协议 在学习了Netty的不同的编码器和解码器之后,我们可以通过编解码器实现简单的自定义协议,这个自定义的协议 ...

  2. hive基础总结(面试常用)

    hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行. Metastore (hiv ...

  3. L2TP连接尝试失败,因为安全层在初始化与远程计算机的协商时遇到了一个处理错误(转)

    L2TP连接尝试失败,因为安全层在初始化与远程计算机的协商时遇到了一个处理错误   错误描述:“ L2TP连接尝试失败,因为安全层在初始化与远程计算机的协商时遇到了一个处理错误” 只有这个没有错误码. ...

  4. 多租户通用权限设计(基于casbin)

    多租户通用权限设计(基于 casbin) 所谓权限控制, 概念并不复杂, 就是确认某个操作是否能做, 本质上仅仅就是个bool判断. 权限几乎是每个系统必不可少的功能, 和具体业务结合之后, 在系统中 ...

  5. ASP.NET Core部署在IIS上

    1.下载安装 Windows Server Hosting ,它的作用是,让IIS有反向代理功能(Asp.Net Core Module负责反向代理工作),将请求转发到 Kestrel 2.发布网站, ...

  6. springmvc源码分析——入门看springmvc的加载过程

    本文将分析springmvc是如何在容器启动的时候将各个模块加载完成容器的创建的. 我知道在web.xml文件中我们是这样配置springmvc的: 可以看到,springmvc的核心控制器就是Dis ...

  7. Wonder 1.0正式版发布-----WebGL 3D引擎和编辑器

    介绍 我们很荣幸地向大家发布Wonder 1.0正式版!免费.开源,不用注册,直接打开在线编辑器即可使用! Wonder是web端3D开发的解决方案,包括引擎.编辑器,致力于打造开放.分享.互助的生态 ...

  8. Linux如何在一个文件中写入内容

    Linux中,在一个文件中写入内容,可以vim打开编辑模式,输入我们想要的内容,此次我们使用echo命令 来在一个文件夹中写入内容. echo命令: 第一种: echo 'i love u' > ...

  9. WordPress博客搭建与问题总结

      一.WordPress博客搭建 1.安装Apache web服务器 yum install -y httpd systemctl restart httpd systemctl enable ht ...

  10. c++ 套路多

    1. 浅拷贝带来的多次析构问题 参见:https://www.cnblogs.com/33debug/p/6657730.html 解决方案,深拷贝.强烈建议自定义拷贝构造函数为深拷贝,否则可能会给自 ...