# String Container

## 字符串拼接

1. '+' ：直接相加，内部实现是创造新的 stringBuilder 然后进行 append 操作然后再 toString() 返回字符串

   ```java
    String a = "abc";
    String b = a + "efg";
   ```
2. concat 方法：先将所有的字符放到一个新的 char\[] 中，然后再创建新的 String

   ```java
    String a = "abc";
    String b = a.concat(",").concat(a);
   ```
3. StringBuilder ：容纳可变长的字符串加减变化，扩容通过继续申请连续的空间，直接将接入的字符串拷贝到自己原先维护的内部 char\[] 中

   ```java
    StringBuilder a = new StringBuilder("init");
    String b = "abc";
    a = a.append(b);
    StringBuilder c = a.append("end"); // c="initabcend"
   ```
4. StringBuffer ：带有 synchronized 的 StringBuffer，其是线程安全的，可以保证多线程中的并发访问

   ```java
    // 查看 StringBuffer 的 append 方法：
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
   ```
5. StringUtils.join() ：将数组或集合 **以某种拼接符拼接到一起**，传入的是一个集合和自定的 separator，内部也是使用 StringBuilder 实现

   ```java
    String []list = {"abc", "def", "ghi"};
    String a = StringUtils.join(list, "-"); // a="abc-def-ghi"
   ```
6. StringJoiner ：JDK8 中的新特性，可以自定义拼接符，前缀和后缀，**更重要的是支持流处理**，内部也是使用 StringBuilder 实现

   ```java
    // Java Doc 的介绍
    // A StringJoiner may be employed to create formatted output 
    //      from a Stream using Collectors.joining(CharSequence)

    // 构造函数
    StringJoiner(CharSequence delimiter);
    StringJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix);

    // 普通操作
    StringJoiner sj = new StringJoiner("COOKIE"); // 注意这里是分隔符不是初始值
    sj.add("abc");
    sj.add("def");
    System.out.println(sj.toString()); // abcCOOKIEdef

    StringJoiner sj1 = new StringJoiner("-","begin:",":end");
    sj1.add("abc").add("def");
    System.out.println(sj1.toString()); // begin:abc-def:end

    // 流操作
    List<String> list = ImmutableList.of("abc","def","ghi");
    list.stream().collect(Collectors.joining("-")); // "abc-def-ghi"

    // 上面的 Collectors.joining() 源码
    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);
    }
   ```

使用的选择：\
1\. 简单的拼接用 '+' 或者 concat 都可以\
2\. for 循环的相加用 StringBuilder 或者 StringBuffer(主要是考虑线程安全)，严格不用 '+'，性能太差 (From Ali Java Manual)\
3\. 通过一个集合（如: List）进行字符串的拼接，可以考虑使用 StringJoiner 或 StringUtils.join()\
4\. 如果对一组数据进行拼接或有前缀后缀分隔符的要求，可以考虑转换为Stream，并使用 StringJoiner 处理

**Reference**\
1\. [Hollis | Java 8中字符串拼接新姿势：StringJoiner](https://mp.weixin.qq.com/s/zC1vQ0m1Vl15VFRxhnSkxA)\
2\. [Hollis | 为什么阿里巴巴不建议在for循环中使用"+"进行字符串拼接](https://mp.weixin.qq.com/s/Zs8en3T8TxCMbxGWHkDwBw)
