字符串拼接新姿势—— Java 8 StringJoiner

前言

平常工做中拼接字符串确定是咱们少不了的操做,最近工做中正好用到了,而后想起前几天看到的Java 8的一个新类:StringJoiner类,因此今天正好来看一看它的源码。bash

正文

用法简介

这个类的用法其实很简单,咱们能够看到源码中给出的例子:app

StringJoiner sj = new StringJoiner(":", "[", "]");
 sj.add("George").add("Sally").add("Fred");
 String desiredString = sj.toString();
复制代码

咱们把这个字符串最终打印出来:less

[George:Sally:Fred]
复制代码

因此基本上能看出一点用法了: 经过带参构造器构造出一个StringJoiner的对象,调用add方法开始拼接字符串,构造器中的参数会决定拼接的字符串的先后缀以及中间的链接符,最终调用toString方法转换为String对象。ide

一张图总览下这个类里都有些什么,后面逐一解释。ui

参数

StringJoiner总共有五个参数:this

private final String prefix;    //前缀
private final String delimiter; //分隔符
private final String suffix;    //后缀
private StringBuilder value;  
private String emptyValue;   
复制代码

后两个参数颇有意思spa

private StringBuilder value; 
实际上是Joiner的底层,说到底StringJoiner仍是调用的StringBuiler方法,只是这层封装里加上了有关于前缀,后缀和链接符的操做,让咱们能够方便一些。
复制代码
private String emptyValue;
 emptyValue 你能够把它看做是当你的StringJoiner对象没有进行任何add的操做时,调用toString() 方法会return 这个字符串而不是空。具体的用法后面看到setEmptyValue的时候再举例子。
复制代码

看下源码注释:指针

/*
     * By default, the string consisting of prefix+suffix, returned by
     * toString(), or properties of value, when no elements have yet been added,
     * i.e. when it is empty.  This may be overridden by the user to be some
     * other value including the empty String.
     */
复制代码
构造器

从大纲里能够看到StringJoiner总共有两个构造器:code

先看参数多的

public StringJoiner(CharSequence delimiter,
                        CharSequence prefix,
                        CharSequence suffix) {
        Objects.requireNonNull(prefix, "The prefix must not be null");
        Objects.requireNonNull(delimiter, "The delimiter must not be null");
        Objects.requireNonNull(suffix, "The suffix must not be null");
        // make defensive copies of arguments
        this.prefix = prefix.toString();
        this.delimiter = delimiter.toString();
        this.suffix = suffix.toString();
        this.emptyValue = this.prefix + this.suffix;
    }
复制代码

这里面三个参数分别是前缀后缀和链接符,而后这里有一个操做就是将emptyValue赋值了前缀+后缀的字符串。也就是说当你用了这个构造器的时候,emptyValue就已经有值了,就是前缀+后缀拼接。当你StringJoiner不执行add方法直接toString()时,会return的对象就是你的前缀+后缀。 例子:cdn

public static void main (String [] args) {

		StringJoiner sj = new StringJoiner(":", "[", "]");
		String desiredString = sj.toString();
		System.out.println(desiredString);
	}

复制代码

这里打印结果就是[]

再看只有一个参数的构造器:

public StringJoiner(CharSequence delimiter) {
        this(delimiter, "", "");
    }
复制代码

其实仍是调用的三参构造器,只不过先后缀默认值为"",也就是没有先后缀。这种状况下emptyValue是什么呢? 其实和上面同样的,""+""就是"",不难理解。

方法

先看上面提到最多的toString().

@Override
    public String toString() {
        if (value == null) {
            return emptyValue;
        } else {
            if (suffix.equals("")) {
                return value.toString();
            } else {
                int initialLength = value.length();
                String result = value.append(suffix).toString();
                // reset value to pre-append initialLength
                value.setLength(initialLength);
                return result;
            }
        }
    }
复制代码

当value为空(也就是StringBuilder为空)时,会return emptyVaule, 若是不为空,就会加上一个给你加后缀的操做。固然这里加后缀你能够看做一次性的,他在加以前会取一个长度,无论你后缀多长,加完以后会set到初始长度。

知道了后缀是这里加的,那前缀呢。

来看最核心的 add方法:

public StringJoiner add(CharSequence newElement) {
        prepareBuilder().append(newElement);
        return this;
    }
复制代码
private StringBuilder prepareBuilder() {
        if (value != null) {
            value.append(delimiter);
        } else {
            value = new StringBuilder().append(prefix);
        }
        return value;
    }
复制代码

前缀就是在你调用第一个add的时候就加上了,为何是第一个呢,由于第一次调用add的时候,你的value确定是空的,因此它会走else的逻辑给你构造一个StringBuilder出来,这个时候会把前缀加好。因此你后面无论有几个add,都是基于一个StringBuilder上在加字符串。当你的value不为空了,就会给你拼接上链接符,最后再拼接上add()方法里的参数。完美。

再结合toString方法来看,当你没有调用过add方法而直接toString时,value为空,它就会return emptyValue了。

再来看个和emptyValue有关的方法setEmptyValue(CharSequence emptyValue):

public StringJoiner setEmptyValue(CharSequence emptyValue) {
        this.emptyValue = Objects.requireNonNull(emptyValue,
            "The empty value must not be null").toString();
        return this;
    }
复制代码

这个方法实际上是暴露给开发者主动设置emptyValue值的方法,也就是说,当你没有调用set方法,emptyValue默认值为前缀+后缀,无论先后缀是否为空;当你调用了set方法,emptyValue就是设置的值。 举个例子:

public static void main (String [] args) {

		StringJoiner sj = new StringJoiner(":", "[", "]");
		sj.setEmptyValue("anson");
		String desiredString = sj.toString();
		System.out.println(desiredString);
	}
复制代码

这里的打印结果就是anson,注意不是[anson]哦。

还有一个有关字符串操做的方法 merge(StringJoiner)

public StringJoiner merge(StringJoiner other) {
        Objects.requireNonNull(other);
        if (other.value != null) {
            final int length = other.value.length();
            // lock the length so that we can seize the data to be appended
            // before initiate copying to avoid interference, especially when
            // merge 'this'
            StringBuilder builder = prepareBuilder();
            builder.append(other.value, other.prefix.length(), length);
        }
        return this;
    }
复制代码

这里面调用了一个StringBuilder的append()重载方法:

public StringBuilder append(CharSequence s, int start, int end) {
        super.append(s, start, end);
        return this;
    }
复制代码

也就是说merge操做是把另外一个StringJoiner(简称sj2)的从前缀开始(不包括前缀)包括链接符可是不包括后缀的字符串加进去sj1里面。

上个例子:

public static void main (String [] args) {

		StringJoiner sj1 = new StringJoiner(":","[","]");
		StringJoiner sj2 = new StringJoiner(",","{","}");
		sj1.add("b");
		sj2.add("a").add("c");
		sj1.merge(sj2);
		String desiredString = sj1.toString();
		System.out.println(desiredString);
	}
复制代码

打印结果:[b:a,c]

先后缀都是sj1的,ac间的链接符是sj2的。

最后再看个简单的方法收尾

public int length() {
        // Remember that we never actually append the suffix unless we return
        // the full (present) value or some sub-string or length of it, so that
        // we can add on more if we need to.
        return (value != null ? value.length() + suffix.length() :
                emptyValue.length());
    }
复制代码

length()方法你们最熟悉,获取长度。这里能看到有一个好处就是当你没有调用add方法也就是没有初始化StringBuilder时,调用这个方法不会空指针,由于有默认的emptyValue。

总结

总结一下,Java 8的新类StringJoiner用法很简单,其实就是一个披着StringJoiner皮的StringBuilder而已嘛。不过有人帮你封装好了加减后缀和链接符的方法也是好的!

相关文章
相关标签/搜索