StringJoiner使用詳解


StringJoiner是java.util包下的一個工具類,jdk1.8出來的

作用是在構造字符串時,可以自動添加前綴、后綴及分隔符,而不需要自己去實現這些添加字符的邏輯

先看一個簡單的demo

StringJoiner sj1 = new StringJoiner(",");
StringJoiner sj2 = new StringJoiner(",", "[", "]");

System.out.println(sj1.add("a").add("b").add("c"));
System.out.println(sj2.add("a").add("b").add("c"));
System.out.println(sj1.merge(sj2));
System.out.println(sj2.merge(sj1));
System.out.println(sj1.length());

image-20200208234335412

StringJoiner有兩個構造方法

  1. 只傳入分隔符

    public StringJoiner(CharSequence delimiter) {
        // 這里只是調用了第二個構造方法,前綴和后綴傳入空字符串,表示沒有前后綴
        this(delimiter, "", "");
    }
    
  2. 傳入分隔符,還有前綴和后綴

    public StringJoiner(CharSequence delimiter,
                        CharSequence prefix,
                        CharSequence suffix) {
        // 做了以下判斷,如果分隔符,前后綴為null,則拋出NullPointerException異常
        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");
        
    	// 賦值給當前對象的屬性
        this.prefix = prefix.toString();
        this.delimiter = delimiter.toString();
        this.suffix = suffix.toString();
        this.emptyValue = this.prefix + this.suffix;
    }
    

成員屬性,其實StringJoiner主要是通過維護了一個StringBuilder對象value去添加元素的

// 當前StringJoiner對象前綴
private final String prefix;
// 每個添加元素的分隔符
private final String delimiter;
// 當前StringJoiner對象后綴
private final String suffix;
// 前綴+元素+分隔符+后綴的值,如果沒有添加元素,那么value是null
private StringBuilder value;
// 前綴+后綴的值,如果沒有前后綴,那么這個值為空字符串,可以理解為value的副本,在value為null時,用它來代替
private String emptyValue;

方法描述及源碼分析

  • public StringJoiner add(CharSequence newElement):添加一個元素,初始化value的工作也是在這里做的,如果當前StringJoiner沒有調用過一次add方法,那么value為null

    public StringJoiner add(CharSequence newElement) {
        // 在此調用prepareBuilder方法,prepareBuilder會自動判斷value是否已經初始化,並添加好分隔符
        prepareBuilder().append(newElement);
        return this;
    }
    
  • private StringBuilder prepareBuilder():在調用add方法時會自動調用,判斷value是否為null,如果不為null,直接添加分隔符。如果為null,構造一個StringBuilder對象,初始值為prefix。

    private StringBuilder prepareBuilder() {
        // 如果不為null,在添加元素前添加分隔符
        if (value != null) {
            value.append(delimiter);
        } else {
            // 反之,構建StringBuilder對象,初始值為prefix
            value = new StringBuilder().append(prefix);
        }
        return value;
    }
    
  • public StringJoiner merge(StringJoiner other):合並一個StringJoiner對象到當前StringJoiner對象

    public StringJoiner merge(StringJoiner other) {
        Objects.requireNonNull(other);
        if (other.value != null) {
            final int length = other.value.length();
            StringBuilder builder = prepareBuilder();
           	// 將傳過來的StringJoiner對象拼接到末尾
            builder.append(other.value, other.prefix.length(), length);
        }
        return this;
    }
    
  • public int length():如果value不為null,當前值=value的長度+suffix的長度,如果為null,返回emptyValue的長度

    public int length() {
        // 如果value為null,返回emptyValue的長度,反之返回value的長度
        return (value != null ? value.length() + suffix.length() :
                emptyValue.length());
    }
    
  • public String toString():如果value不為null,返回value+suffix的值,如果為null,返回emptyValue

    @Override
    public String toString() {
        // value為null用emptyValue來代替
        if (value == null) {
            return emptyValue;
        } else {
            // 沒有后綴直接返回value字符串
            if (suffix.equals("")) {
                return value.toString();
            } else {
                // 有后綴需要在toString里面再補上,把當前對象作為字符串使用時,toString方法會自動調用
                int initialLength = value.length();
                String result = value.append(suffix).toString();
                // reset value to pre-append initialLength
                value.setLength(initialLength);
                return result;
            }
        }
    }
    

如果是想將一個list中的元素快速的以這種方式添加,可以通過String.join來實現

// 第一個參數是分隔符,第二個參數是list
System.out.println(String.join(",", Arrays.asList("a", "b", "c")));
// 第二個參數是可變數組
System.out.println(String.join(",", "a", "b", "c"));

image-20200209083456237

String.join方法也是jdk1.8出來的

查看String.join的源碼可以看見,里面其實就是構建了一個StringJoiner對象,它只指定了分隔符,所以String.join不能實現有前后綴的情況

public static String join(CharSequence delimiter,
        Iterable<? extends CharSequence> elements) {

    Objects.requireNonNull(delimiter);
    Objects.requireNonNull(elements);
    
    // 構建了一個指定分隔符的StringJoiner對象
    StringJoiner joiner = new StringJoiner(delimiter);
    // 循環添加list中的元素
    for (CharSequence cs: elements) {
        joiner.add(cs);
    }
    return joiner.toString();
}

如果想處理list添加前后綴的問題,可以通過list的stream流的collect方法來處理,需要配合Collectors.joining方法

Collectors.joining(CharSequence delimiter);
Collectors.joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix);

將list通過stream方法轉成流之后調用collect來返回想要的結果集

List<String> list1 = Arrays.asList("a", "b", "c");
List<String> list2 = Arrays.asList("a", "b", "c");

System.out.println(list1.stream().collect(Collectors.joining(",")));
System.out.println(list2.stream().collect(Collectors.joining(",", "[", "]")));

image-20200209085226721

查看Collectors.joining源碼實現,發現其中也是維護了一個StringJoiner實例去做這些事

public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
                                                         CharSequence prefix,
                                                         CharSequence suffix) {
    return new CollectorImpl<>(
            () -> new StringJoiner(delimiter, prefix, suffix),
            StringJoiner::add, StringJoiner::merge,
            StringJoiner::toString, CH_NOID);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM