# 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)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://legacy.cookielau.com/archives/2-java/1-stringcontainer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
