• [源码分析]Java1.8中StringJoiner的使用以及源码分析


    [源码分析]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里.

  • 相关阅读:
    java多线程学习-同步之线程通信
    java多线程学习-同步(synchronized)
    java多线程学习-开篇
    面向对象-多线程-异常机制-查漏补缺
    Sprin2.5+Hibernate3.3+Struts2.0.11集成
    Strut1.3+Sprin2.5+Hibernate3.3集成
    Sprin2.5+Hibernate3.3集成
    Spring学习笔记
    Hibernate学习笔记
    Sping
  • 原文地址:https://www.cnblogs.com/noKing/p/java_source_StringJoiner.html
Copyright © 2020-2023  润新知